GOAL

The aim of this script is to compare if there is a systemic bias between WGBS processed samples and targeted sequenced samples and to remove it. Also, the targeted sequencing data functions as validation cohort for the DMRs identified from the discovery cohort.

Conclusion

The sequencing bias could best be removed by combining a quantile normalisation with a ComBat adjustment.Further approaches e.g. winsorization have been also tested in this script.

Load Libraries

library(tidyverse)
library(DescTools)
library(preprocessCore)
library(ggfortify)
library(sva)
Loading required package: mgcv
Loading required package: nlme

Attaching package: 'nlme'

The following object is masked from 'package:dplyr':

    collapse

This is mgcv 1.8-40. For overview type 'help("mgcv-package")'.
Loading required package: genefilter

Attaching package: 'genefilter'

The following object is masked from 'package:DescTools':

    AUC

The following object is masked from 'package:readr':

    spec

Loading required package: BiocParallel
library(ggpubr)
library(ggrepel)

Set Theme

theme_Publication <- function(base_size=14, base_family="sans") {
      library(grid)
      library(ggthemes)
      (theme_foundation(base_size=base_size, base_family=base_family)
       + theme(plot.title = element_text(face = "bold",
                                         size = rel(1.2), hjust = 0.5, margin = margin(0,0,20,0)),
               text = element_text(),
               panel.background = element_rect(colour = NA),
               plot.background = element_rect(colour = NA),
               panel.border = element_rect(colour = NA),
               axis.title = element_text(face = "bold",size = rel(1)),
               axis.title.y = element_text(angle=90,vjust =2),
               axis.title.x = element_text(vjust = -0.2),
               axis.text = element_text(), 
               axis.line.x = element_line(colour="black"),
               axis.line.y = element_line(colour="black"),
               axis.ticks = element_line(),
               panel.grid.major = element_line(colour="#f0f0f0"),
               panel.grid.minor = element_blank(),
               legend.key = element_rect(colour = NA),
               legend.position = "bottom",
               legend.direction = "horizontal",
               legend.box = "vetical",
               legend.key.size= unit(0.5, "cm"),
               #legend.margin = unit(0, "cm"),
               legend.title = element_text(face="italic"),
               plot.margin=unit(c(10,5,5,5),"mm"),
               strip.background=element_rect(colour="#f0f0f0",fill="#f0f0f0"),
               strip.text = element_text(face="bold")
       ))
      
}

Define Inputs

meth_perc_all_tiles_validation <- readRDS(file = "/local/rcuadrat/data_for_altuna/methyl_perc_all_tiles_no_CAD_validation.RDS")
meth_perc_all_tiles_WGBS <- readRDS(file = "/local/rcuadrat/data_for_altuna/methyl_perc_all_tiles_no_CAD_WGBS.RDS")

metadata <- readRDS(file = "/local/rcuadrat/data_for_altuna/metadata_no_CAD.RDS")
data_for_scatterplot <- readRDS(file = "/local/rcuadrat/data_for_altuna/data_for_scatterplot.rds")

methylBaseDB_validation_no_CAD <- readRDS("/local/rcuadrat/data_for_altuna/methylBaseDB_validation_no_CAD.RDS")
methylBaseDB_WGBS_all_samples <- readRDS("/local/rcuadrat/data_for_altuna/methylBaseDB_WGBS_all_samples.RDS")

methylDiff_WGBS <- readRDS(file= "/local/AAkalin_cardiac/Results/cardiac/RDS/myDiff25p_tiled_list_v1.RDS")
methylDiff_validation<- readRDS(file= "/local/rcuadrat/data_for_altuna/methylDiff_validation_ACS.RDS")

methylDiff_WGBS <- methylDiff_WGBS[1:3]
names(methylDiff_WGBS)<-c("STEMI", "NSTEMI", "UA")
methylDiff_WGBS <- methylDiff_WGBS %>% map2(names(.), ~ as_tibble(.x) %>% 
                                              add_column(condition=.y) %>% 
                                              tidyr::unite(tiles, seqnames, start, end, condition, sep="."))

methylDiff_validation <- methylDiff_validation %>% map2(names(.), ~ methylKit::getData(.x) %>% 
                                                          as_tibble(.x) %>% 
                                                          add_column(condition=.y) %>% 
                                                          tidyr::unite(tiles, chr, start, end, condition, sep="."))

clinical_markers<-readxl::read_excel("/local/AAkalin_cardiac/metadata/WGBS_ShortTableCorrelations.xlsx")
suppl_tbl_2 <- readRDS("/local/rcuadrat/cfdna_wgbs/suppl_tbl_2.RDS")
clinical_markers<-merge(suppl_tbl_2,clinical_markers,by="Sample")
#clinical_markers = clinical_markers %>% rename("CRP (mg/dl)"="CRP(mg/dl_<5)","TroponinT (ng/l)"="TroponinThs_t1 (ng/l <14or<50)","CK (U/l)"="CK (U/l _<190)","CK max (U/l)"="CKmax(U/l_<190)","CK-MB (U/l)"="CK-MB(U/l <24)","CK-MB max (U/l)"="CK-MB_Max")
clinical_markers_ACS<-clinical_markers %>% filter(treatment !=0)

Analysis

All Data

seq_method <- rep(c("WGBS", "targeted"), times = c(29, 11))
metadata$seq_method <- seq_method

metadata <- metadata %>%
  mutate(condition = case_when(
    (treatment == 0) ~ "Control",
    (treatment == 1) ~ "STEMI",
    (treatment == 2) ~ "NSTEMI",
    (treatment == 3) ~ "UA"
  ))
nrow(meth_perc_all_tiles_validation)
[1] 10138
length(setdiff(rownames(meth_perc_all_tiles_validation), rownames(meth_perc_all_tiles_WGBS)))
[1] 1026
length(intersect(rownames(meth_perc_all_tiles_validation), rownames(meth_perc_all_tiles_WGBS)))
[1] 9112
all_common_tiles<-intersect(rownames(meth_perc_all_tiles_validation), rownames(meth_perc_all_tiles_WGBS))

Find out if tiles which do not match WGBS are mapping to specific location Altuna:“…we have designed probes for 10K regions but for whatever reason some probes don’t work that’s why targeted sequencing doesn’t cover whole 10K tiles but same tiles exist on WGBS because that was the basis of our design. losing probes are expected, the efficiency of targeting is 80-90%”

missing_tiles <- setdiff(rownames(meth_perc_all_tiles_validation), rownames(meth_perc_all_tiles_WGBS))

missing_tiles <- tibble(missing_tiles) %>%
  separate(missing_tiles, into = c("chrom", "start", "end"), sep = "\\.") %>%
  arrange(chrom, start, end)

Map corresponding tiles of both seq methods in one

overlap_tiles_validation_WGBS <- inner_join(x=as_tibble(meth_perc_all_tiles_validation, rownames = "tiles"), y=as_tibble(meth_perc_all_tiles_WGBS, rownames = "tiles"))
Joining, by = "tiles"

Transform to long format

all_data <- overlap_tiles_validation_WGBS %>%
  pivot_longer(-tiles, names_to = "sample_ids", values_to = "perc_meth") %>%
  left_join(metadata, by = "sample_ids") %>%
  mutate(treatment = as.factor(treatment))

Raw Data

Compare how mean difference in methylation is distributed

Compare difference of mean of all all common tiles between targeted and WGBS from raw data

# Map metadata and pivot
overlap_tiles_validation_WGBS_mean <- overlap_tiles_validation_WGBS %>%
  pivot_longer(-tiles, names_to = "sample_ids", values_to = "perc_meth") %>%
  left_join(metadata, by = "sample_ids") %>%
  mutate(treatment = as.factor(treatment))

#calculate mean per condition
overlap_tiles_validation_WGBS_mean <- overlap_tiles_validation_WGBS_mean %>%
  group_by(tiles, seq_method, condition) %>%
  summarise_at(vars(perc_meth), list(name = mean))
overlap_tiles_validation_WGBS_mean <-
  dplyr::rename(overlap_tiles_validation_WGBS_mean, mean = "name")

#calculate difference of means
overlap_tiles_validation_WGBS_mean_diff <- overlap_tiles_validation_WGBS_mean %>%
  pivot_wider(values_from = mean, names_from =condition) %>%
  mutate(meth.diff_STEMI = STEMI - Control,
         meth.diff_NSTEMI = NSTEMI - Control,
         meth.diff_UA = UA - Control) %>%
  dplyr::select(-c(Control, NSTEMI, STEMI, UA)) %>%
  dplyr::rename(STEMI = "meth.diff_STEMI", 
                NSTEMI ="meth.diff_NSTEMI", 
                UA = "meth.diff_UA") %>%
  pivot_longer(-c(tiles, seq_method), names_to = "condition", values_to = "meth_diff" ) %>%
  pivot_wider(names_from = "seq_method", values_from ="meth_diff") %>%
  dplyr::rename(meth.diff.WGBS = "WGBS", meth.diff.targeted = "targeted")


#Calculate threshold for scatterplot
overlap_tiles_validation_WGBS_mean_diff <- overlap_tiles_validation_WGBS_mean_diff %>% 
  mutate(threshold_25= case_when((((25 <= meth.diff.WGBS) & (25 <= meth.diff.targeted))  | (((meth.diff.WGBS <=-25) & (meth.diff.targeted <=-25))) ) ~ "|25%|", TRUE ~ "not in range"))


# Plot
overlap_tiles_validation_WGBS_mean_diff %>%
  ggplot(aes(x = meth.diff.targeted, y = meth.diff.WGBS, colour=threshold_25)) +
  geom_point(shape = 16, size=2, alpha=0.6) +
  stat_cor(method="pearson")+
  geom_vline(xintercept = c(-25, 25), linetype="dotted")+
  geom_hline(yintercept = c(-25, 25), linetype="dotted")+
  ylab("Mean Methylation Difference WGBS") +
  xlab("Mean Methylation Difference Targeted Sequencing") +
  labs(title = "Raw Data \nAll Common Tiles", colour="Threshold") +
  theme(plot.title = element_text(hjust = 0.5, face ="bold", size=16), aspect.ratio = 1) +
  scale_color_manual(values=c("#919494", "#7CAE00"))+
  facet_grid(cols = vars(condition))


p28 <-
  overlap_tiles_validation_WGBS_mean_diff %>%
  ggplot(aes(x = condition, y = meth.diff.targeted, fill = condition)) +
  geom_boxplot(outlier.shape = NA) +
  ylab("Mean Methylation Difference [%]") +
  xlab("ACS Type") +
  labs(title = "Targeted Sequencing") +
  scale_fill_discrete(name = "ACS Type") +
  theme(plot.title = element_text(hjust = 0.5)) +
  ylim(-100, 100)

p29 <-
  overlap_tiles_validation_WGBS_mean_diff %>%
  ggplot(aes(x = condition, y = meth.diff.WGBS, fill = condition)) +
  geom_boxplot(outlier.shape = NA) +
  ylab("Mean Methylation Difference [%]") +
  xlab("ACS Type") +
  labs(title = "WGBS") +
  scale_fill_discrete(name = "ACS Type") +
  ylim(-100, 100) +
  theme(plot.title = element_text(hjust = 0.5))

annotate_figure(ggarrange(p28, p29, nrow=1, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Raw Data \nAll Common Tiles", face = "bold", size=16))

Winsorization

tiles <- unlist(overlap_tiles_validation_WGBS[, 1])

overlap_tiles_validation_WGBS_winsorized <- as_tibble(lapply(overlap_tiles_validation_WGBS[, -1], Winsorize, probs = c(0.1, 0.9))) %>% 
  add_column(tiles = tiles, .before = "2017") %>%
  pivot_longer(-tiles, names_to = "sample_ids", values_to = "perc_meth") %>%
  left_join(metadata, by = "sample_ids") %>%
  mutate(treatment = as.factor(treatment))

# Plot data to compare methylation between treated diseases
p8 <- overlap_tiles_validation_WGBS_winsorized %>%
  ggplot(aes(x = condition, y = perc_meth, fill = seq_method)) +
  geom_boxplot() +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5))

p9 <- overlap_tiles_validation_WGBS_winsorized %>%
  ggplot(aes(x = condition, y = perc_meth, fill = seq_method)) +
  geom_violin() +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5))

p10 <- overlap_tiles_validation_WGBS_winsorized %>% ggplot(aes(x = condition, y = perc_meth)) +
  geom_violin(aes(fill = seq_method)) +
  geom_boxplot(aes(fill = seq_method), width = 0.05) +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5)) +
  facet_grid(seq_method ~ .)

p11 <- overlap_tiles_validation_WGBS_winsorized %>% ggplot(aes(x = condition, y = perc_meth)) +
  geom_violin(fill = "#7C7CFF") +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5))

annotate_figure(ggarrange(p8, p9, p10, p11, common.legend = TRUE, legend="right", labels="AUTO", nrow=2, ncol=2), text_grob("Windsorized Data \nAll Common Tiles", face = "bold", size=16))


p12 <- overlap_tiles_validation_WGBS_winsorized %>%
  filter(seq_method == "WGBS") %>%
  ggplot(aes(x = sample_ids, y = perc_meth)) +
  geom_violin(fill = "#F8766D") +
  geom_boxplot(width = 0.05) +
  ylab("Methylation [%]") +
  xlab("Sample") +
  labs(title = "WGBS") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5), axis.text.x = element_text(angle = 45, vjust = 0.8, hjust = 1))

p13 <- overlap_tiles_validation_WGBS_winsorized %>%
  filter(seq_method == "targeted") %>%
  ggplot(aes(x = sample_ids, y = perc_meth)) +
  geom_violin(fill = "#00BFC4") +
  geom_boxplot(width = 0.05) +
  ylab("Methylation [%]") +
  xlab("Sample") +
  labs(title = "Targeted") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5))

overlap_tiles_validation_WGBS_winsorized %>% ggplot(aes(x = sample_ids, y = perc_meth, fill = seq_method)) +
  geom_violin() +
  geom_boxplot(width = 0.05) +
  ylab("Methylation [%]") +
  xlab("Sample") +
  labs(title = "Windsorized Data\nAll Common Tiles") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5, face="bold", size=16), axis.text.x = element_text(angle = 45, vjust = 0.8, hjust = 1))


annotate_figure(ggarrange(p12, p13, nrow=2, ncol=1, labels="AUTO"), text_grob("Windsorized Data \nAll Common Tiles", face = "bold", size=16))

Quantile Normalisation

# Seperate targeted and WGBS data into two tibbles
targeted_meth_perc <- overlap_tiles_validation_WGBS %>% dplyr::select((metadata %>% filter(seq_method == "targeted"))$sample_ids)
WGBS_meth_perc <- overlap_tiles_validation_WGBS %>% dplyr::select((metadata %>% filter(seq_method == "WGBS"))$sample_ids)

# make WGBS data a vector
WGBS_meth_perc_distribution <- c(t(WGBS_meth_perc))

# normalise and assign column names to data
targeted_meth_perc_normalised <- normalize.quantiles.use.target(as.matrix(targeted_meth_perc), WGBS_meth_perc_distribution, copy = TRUE) %>% as_tibble()
colnames(targeted_meth_perc_normalised) <- colnames(targeted_meth_perc)

# add tiles column and join both dataframes
targeted_meth_perc_normalised <- targeted_meth_perc_normalised %>%
  add_column(tiles = tiles, .before = "2017")
WGBS_meth_perc <- WGBS_meth_perc %>%
  add_column(tiles = tiles, .before = "N1")

overlap_normalised <- WGBS_meth_perc %>% left_join(targeted_meth_perc_normalised, by = "tiles")

# map metadata and pivot
overlap_normalised <- overlap_normalised %>%
  pivot_longer(-tiles, names_to = "sample_ids", values_to = "perc_meth") %>%
  left_join(metadata, by = "sample_ids") %>%
  mutate(treatment = as.factor(treatment))
p14 <- overlap_normalised %>% ggplot(aes(x = condition, y = perc_meth, fill = seq_method)) +
  geom_boxplot() +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5))

p15 <- overlap_normalised %>% ggplot(aes(x = condition, y = perc_meth, fill = seq_method)) +
  geom_violin() +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5))

p16 <- overlap_normalised %>% ggplot(aes(x = condition, y = perc_meth)) +
  geom_violin(aes(fill = seq_method)) +
  geom_boxplot(aes(fill = seq_method), width = 0.05) +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5)) +
  facet_grid(seq_method ~ .)

p17 <- overlap_normalised %>% ggplot(aes(x = condition, y = perc_meth)) +
  geom_violin(fill = "#7C7CFF") +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5))

annotate_figure(ggarrange(p14, p15, p16, p17, nrow=2, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Quantile Normalised Data \nAll Common Tiles", face = "bold", size=16))


p18 <- overlap_normalised %>%
  filter(seq_method == "targeted") %>%
  ggplot(aes(x = sample_ids, y = perc_meth)) +
  geom_violin(fill = "#00BFC4") +
  geom_boxplot(width = 0.05) +
  ylab("Methylation [%]") +
  xlab("Sample") +
  labs(title = "Targeted Sequencing") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5), axis.text.x = element_text(angle = 45, vjust = 0.8, hjust = 1))

p19 <- overlap_normalised %>%
  filter(seq_method == "WGBS") %>%
  ggplot(aes(x = sample_ids, y = perc_meth)) +
  geom_violin(fill = "#F8766D") +
  geom_boxplot(width = 0.05) +
  ylab("Methylation [%]") +
  xlab("Sample") +
  labs(title = "WGBS") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5), axis.text.x = element_text(angle = 45, vjust = 0.8, hjust = 1))

overlap_normalised %>% ggplot(aes(x = sample_ids, y = perc_meth, fill = seq_method)) +
  geom_violin() +
  geom_boxplot(width = 0.05) +
  ylab("Methylation [%]") +
  xlab("Sample") +
  labs(title = "Quantile Normalised Data") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5, face="bold", size=16), axis.text.x = element_text(angle = 45, vjust = 0.8, hjust = 1))


annotate_figure(ggarrange(p18, p19, nrow=2, ncol=1, labels="AUTO"), text_grob("Quantile Normalised Data \nAll Common Tiles", face = "bold", size=16))

overlap_normalised_mean <- overlap_normalised %>%
  group_by(tiles, seq_method, condition) %>%
  summarise_at(vars(perc_meth), list(name = mean))
overlap_normalised_mean <- dplyr::rename(overlap_normalised_mean, mean = "name")

overlap_normalised_mean_diff <- overlap_normalised_mean %>%
  pivot_wider(values_from = mean, names_from = condition) %>%
  mutate(
    meth.diff_STEMI = STEMI - Control,
    meth.diff_NSTEMI = NSTEMI - Control,
    meth.diff_UA = UA - Control
  ) %>%
  dplyr::select(-c(Control, NSTEMI, STEMI, UA)) %>%
  dplyr::rename(STEMI = "meth.diff_STEMI", NSTEMI = "meth.diff_NSTEMI", UA = "meth.diff_UA") %>%
  pivot_longer(-c(tiles, seq_method),
    names_to = "condition",
    values_to = "meth_diff"
  ) %>%
  pivot_wider(names_from = "seq_method", values_from = "meth_diff") %>%
  dplyr::rename(meth.diff.WGBS = "WGBS", meth.diff.targeted = "targeted")

data_for_scatterplot <- data_for_scatterplot %>% tidyr::unite(tiles, seqnames, start, end, group, sep = ".")

overlap_DM_data_normalised_mean_diff <- overlap_normalised_mean_diff %>%
  tidyr::unite(tiles, tiles, condition, sep = ".") %>%
  filter(tiles %in% c(data_for_scatterplot$tiles))

data_for_scatterplot <- data_for_scatterplot %>% tidyr::separate(tiles, into = c("seqnames", "start", "end", "group"), sep = "\\.")

overlap_DM_data_normalised_mean_diff <- overlap_DM_data_normalised_mean_diff %>% tidyr::separate(tiles, into = c("chrom", "start", "end", "condition"), sep = "\\.")

Compare relationship between raw and normalised data and seq technique


#Calculate threshold for scatterplot
data_for_scatterplot <- data_for_scatterplot %>% 
  mutate(threshold_25= case_when((((25 <= meth.diff.x) & (25 <= meth.diff.y))  | (((meth.diff.x <=-25) & (meth.diff.y <=-25))) ) ~ "|25%|", TRUE ~ "not in range"))

overlap_DM_data_normalised_mean_diff <- overlap_DM_data_normalised_mean_diff %>% 
  mutate(threshold_25= case_when((((25 <= meth.diff.targeted) & (25 <= meth.diff.WGBS))  | (((meth.diff.targeted <=-25) & (meth.diff.WGBS <=-25))) ) ~ "|25%|", TRUE ~ "not in range"))


p20 <- data_for_scatterplot %>% 
  ggplot(aes(x = meth.diff.x, y = meth.diff.y, colour=threshold_25)) +
  geom_point(shape = 16, size=2, alpha=0.6) +
  geom_vline(xintercept = c(-25, 25), linetype="dotted")+
  geom_hline(yintercept = c(-25, 25), linetype="dotted")+
  ylab("Weighted Mean Methylation \nDifference Y") +
  xlab("Weighted Mean Methylation \nDifference X") +
  labs(title = "Raw Data \nCoverage Weighted", colour="Threshold") +
  stat_cor(method="pearson")+
  ylim(-100, 100) +
  xlim(-100, 100) +
  theme(plot.title = element_text(hjust = 0.5, face="bold", size=16), aspect.ratio = 1) +
  scale_color_manual(values=c("#919494", "#7CAE00"))+
  facet_grid(cols = vars(group))

p21 <- overlap_DM_data_normalised_mean_diff %>% 
  ggplot(aes(x = meth.diff.targeted, y = meth.diff.WGBS, colour=threshold_25)) +
  geom_point(shape = 16, size=2, alpha=0.6) +
  geom_vline(xintercept = c(-25, 25), linetype="dotted")+
  geom_hline(yintercept = c(-25, 25), linetype="dotted")+
  ylab("Mean Methylation Difference WGBS") +
  xlab("Mean Methylation Difference \nTargeted Sequencing") +
  labs(title = "Quantile Normalised Data", colour="Threshold") +
  stat_cor(method="pearson")+
  ylim(-100, 100) +
  xlim(-100, 100) +
  theme(plot.title = element_text(hjust = 0.5, face="bold", size=16), aspect.ratio = 1) +
  scale_color_manual(values=c( "#919494", "#7CAE00"))+
  facet_grid(cols = vars(condition))

annotate_figure(ggarrange(p20, p21, labels="AUTO", nrow=2, ncol=1), text_grob("DM Tiles", face = "bold", size=16))

Include weighting by coverage

Use weighted methylation differences for WGBS data

data_for_scatterplot <- data_for_scatterplot %>% tidyr::unite(tiles, seqnames, start, end, group, sep = ".")

diff_meth_tiles <- data_for_scatterplot$tiles

diff.meth.y.weighted <- data_for_scatterplot %>% dplyr::select(tiles, meth.diff.y)

overlap_DM_data_normalised_mean_diff <- overlap_DM_data_normalised_mean_diff %>%
  tidyr::unite(tiles, chrom, start, end, condition, sep = ".") %>%
  left_join(diff.meth.y.weighted, by = "tiles") %>%
  tidyr::separate(tiles, into = c("chrom", "start", "end", "condition"), sep = "\\.")

overlap_DM_data_normalised_mean_diff <- overlap_DM_data_normalised_mean_diff %>% 
  mutate(threshold_25_y_weighted= case_when((((25 <= meth.diff.targeted) & (25 <= meth.diff.y))  | (((meth.diff.targeted <=-25) & (meth.diff.y <=-25))) ) ~ "|25%|", TRUE ~ "not in range"))


p22 <- overlap_DM_data_normalised_mean_diff %>% ggplot(aes(x = meth.diff.targeted, y = meth.diff.y, colour=threshold_25_y_weighted)) +
  geom_point(shape = 16, size=2, alpha=0.6) +  
  geom_vline(xintercept = c(-25, 25), linetype="dotted")+
  geom_hline(yintercept = c(-25, 25), linetype="dotted")+
  ylab("Weighted Mean Methylation \nDifference WGBS") +
  xlab("Mean Methylation Difference \nTargeted Sequencing") +
  labs(title = "Quantile Normalised Data", colour="Threshold") +
  stat_cor(method="pearson")+
  ylim(-100, 100) +
  xlim(-100, 100) +
  theme(plot.title = element_text(hjust = 0.5, face="bold", size=16), aspect.ratio = 1) +
  scale_color_manual(values=c("#919494", "#7CAE00"))+
  facet_grid(cols = vars(condition))

annotate_figure(ggarrange(p20, p22, labels="AUTO", nrow=2, ncol=1), text_grob("DM Tiles", face = "bold", size=16))

From targeted sequencing, what percentage lies above or below +-25%?

data_for_scatterplot <- data_for_scatterplot %>% separate(tiles, into = c("seqnames", "start", "end", "group"), sep = "\\.")


raw_validated <- data_for_scatterplot %>%
  group_by(group) %>%
  dplyr::count(meth.diff.x <=-25 | meth.diff.x >=25) %>% 
  dplyr::rename(threshold_25=2) %>% 
  pivot_wider(names_from=threshold_25, values_from=n) %>%
  dplyr::rename(Validated=3, Not_Validated=2) %>%
  mutate(percentage=(Validated/(Not_Validated+Validated)*100))

print(raw_validated)

norm_validated <- overlap_DM_data_normalised_mean_diff %>%
  group_by(condition) %>%
  dplyr::count(meth.diff.targeted <=-25 | meth.diff.targeted >=25) %>% 
  dplyr::rename(threshold_25=2) %>% 
  pivot_wider(names_from=threshold_25, values_from=n) %>%
  dplyr::rename(Validated=3, Not_Validated=2) %>%
  mutate(percentage=(Validated/(Not_Validated+Validated)*100))

print(norm_validated)

Distribution of differentially methylated tiles

p23 <- overlap_DM_data_normalised_mean_diff %>%
  ggplot(aes(x = condition, y = meth.diff.targeted, fill = condition)) +
  geom_boxplot() +
  ylab("Mean Methylation Difference [%]") +
  xlab("ACS Type") +
  labs(title = "Targeted Sequencing") +
  scale_fill_discrete(name = "ACS Type") +
  theme(plot.title = element_text(hjust = 0.5, face="bold")) +
  ylim(-100, 80)

p24 <- overlap_DM_data_normalised_mean_diff %>%
  ggplot(aes(x = condition, y = meth.diff.WGBS, fill = condition)) +
  geom_boxplot() +
  ylab("Mean Methylation Difference [%]") +
  xlab("ACS Type") +
  labs(title = "WGBS") +
  scale_fill_discrete(name = "ACS Type") +
  ylim(-100, 80) +
  theme(plot.title = element_text(hjust = 0.5, face="bold"))

p25 <- overlap_DM_data_normalised_mean_diff %>%
  ggplot(aes(x = condition, y = meth.diff.y, fill = condition)) +
  geom_boxplot() +
  ylab("Weighted Mean Methylation Difference [%]") +
  xlab("ACS Type") +
  labs(title = "Coverage Weighted \nWGBS") +
  scale_fill_discrete(name = "ACS Type") +
  theme(plot.title = element_text(hjust = 0.5, face="bold")) +
  ylim(-100, 80)

annotate_figure(ggarrange(p23, p24, p25, nrow=1, ncol=3, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Quantile Normalised Data \nDM Tiles", face = "bold", size=16))

Distribution from all common Tiles

p26 <- overlap_normalised_mean_diff %>% ggplot(aes(x = condition, y = meth.diff.targeted, fill = condition)) +
  geom_boxplot() +
  ylab("Mean Methylation Difference [%]") +
  xlab("ACS Type") +
  labs(title = "Targeted Sequencing") +
  scale_fill_discrete(name = "ACS Type") +
  theme(plot.title = element_text(hjust = 0.5, face="bold")) +
  ylim(-100, 100)

p27 <- overlap_normalised_mean_diff %>% ggplot(aes(x = condition, y = meth.diff.WGBS, fill = condition)) +
  geom_boxplot() +
  ylab("Mean Methylation Difference [%]") +
  xlab("ACS Type") +
  labs(title = "WGBS") +
  scale_fill_discrete(name = "ACS Type") +
  ylim(-100, 100) +
  theme(plot.title = element_text(hjust = 0.5, face="bold") )

annotate_figure(ggarrange(p26, p27, nrow=1, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Quantile Normalised Data \nAll Common Tiles", face = "bold", size=16))

Use PCA per condition on quantile normalised patient samples to depict differences between targeted seq and WGBS

overlap_normalised_pca <- overlap_normalised %>% 
  group_by(condition)
overlap_normalised_pca <- group_split(overlap_normalised_pca)
names(overlap_normalised_pca) <- c("Control", "NSTEMI", "STEMI", "UA")

overlap_normalised_pca <- overlap_normalised_pca %>%
  map(~ dplyr::select(., tiles, perc_meth, sample_ids, seq_method) %>%
    pivot_wider(names_from = tiles, values_from = perc_meth))%>%
  map2(names(.), ~ autoplot(prcomp(dplyr::select(.x, starts_with("chr"))), data = .x, colour = "seq_method") +
    labs(title = .y, colour="Sequencing method") +
    theme(plot.title = element_text(hjust = 0.5, face="bold"), , aspect.ratio = 1))

annotate_figure(ggarrange(plotlist = overlap_normalised_pca, nrow=2, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Quantile Normalised Data \nAll Common Tiles", face = "bold", size=16))

–> the seq bias is still visible even though quantile normalisation

ComBat Adjust with Quantile Normalisation

Log transformation of raw data

log_fun <- function(observed) {
  result <- (log((observed + 1) / ((100 - observed) + 1)))
}

overlap_log <- overlap_tiles_validation_WGBS %>%
  dplyr::select_if(is.numeric) %>%
  mutate_all(list(log = ~ log_fun(.))) %>%
  inner_join(overlap_tiles_validation_WGBS) %>%
  dplyr::select(-c(1:40)) %>%
  relocate("tiles") %>%
  pivot_longer(-tiles, names_to = "sample_ids", values_to = "log_transf_perc_meth") %>%
  mutate(across("sample_ids", str_replace, "_log", "")) %>%
  left_join(metadata %>% dplyr::select(sample_ids, condition, seq_method), by = "sample_ids")
Joining, by = c("2017", "2018", "2019", "2026", "2027", "2033", "3052", "3131", "3158", "SK", "VF", "N1", "N2", "N3", "N4", "N5", "N6", "H26", "H28", "AC1", "AC2", "AC3", "AC4", "AC5", "AC6",
"AC14", "AC15", "AC7", "AC8", "AC9", "AC10", "AC11", "AC12", "AC13", "AP1", "AP2", "AP3", "AP4", "AP5", "AP6")

PCA from raw data all diseases in log space all common tiles

PCAs from raw data seperate diseases in log space common tiles

overlap_grouped_log <- overlap_log %>% 
  group_by(condition) %>% 
  group_split()
names(overlap_grouped_log) <- c("Control", "NSTEMI", "STEMI", "UA")

overlap_grouped_log_pca <- overlap_grouped_log %>%
  lapply(FUN = function(x) {
    x %>%
      dplyr::select(tiles, log_transf_perc_meth, sample_ids) %>%
      pivot_wider(names_from = tiles, values_from = log_transf_perc_meth) %>%
      left_join(metadata %>% dplyr::select(sample_ids, seq_method, condition), by = "sample_ids")
  })

# Plot
overlap_grouped_log_pca_plot <- overlap_grouped_log_pca %>%
  map2(
    names(.),
    ~ autoplot(prcomp(dplyr::select(.x, starts_with("chr"))), data = .x, colour = "seq_method") +
      labs(title = .y, colour="Sequencing \nmethod") +
      theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1)
  )

annotate_figure(ggarrange(plotlist =overlap_grouped_log_pca_plot , nrow=2, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Raw Data Log Space \nAll Common Tiles", face = "bold", size=16))

PCAs from raw data seperate diseases in log space DM tiles

overlap_DM_log <- overlap_log %>%
  tidyr::unite(tiles, tiles, condition, sep = ".") %>%
  filter(tiles %in% c(diff_meth_tiles)) %>%
  tidyr::separate(tiles, into = c("chrom", "start", "end", "condition"), sep = "\\.") %>%
  tidyr::unite(tiles, chrom, start, end, sep = ".")

overlap_DM_grouped_log_pca <- overlap_DM_log %>% 
  group_by(condition) %>% 
  group_split()

names(overlap_DM_grouped_log_pca) <- c("NSTEMI", "STEMI", "UA")

overlap_DM_grouped_log_pca <- overlap_DM_grouped_log_pca %>%
  lapply(FUN = function(x) {
    x %>%
      dplyr::select(tiles, log_transf_perc_meth, sample_ids) %>%
      pivot_wider(names_from = tiles, values_from = log_transf_perc_meth) %>%
      left_join(metadata %>% dplyr::select(sample_ids, seq_method, condition), by = "sample_ids")
  })

# Plot
overlap_DM_grouped_log_pca_plot <- overlap_DM_grouped_log_pca %>%
  map2(
    names(.),
    ~ autoplot(prcomp(dplyr::select(.x, starts_with("chr"))), data = .x, colour = "seq_method") +
      labs(title = .y, colour="Sequencing \nmethod") +
      theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1)
  )

annotate_figure(ggarrange(plotlist =overlap_DM_grouped_log_pca_plot , nrow=2, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Raw Data Log Space \nDM Tiles", face = "bold", size=16))

Calculate quantile normalised and combated data per condition

# Perform quantile normalisation 
# Seperate targeted and WGBS data into two tibbles
overlap_grouped_log_targeted <- overlap_grouped_log %>% 
  map(~ dplyr::filter(., seq_method=='targeted')%>% 
        pivot_wider(names_from = sample_ids, values_from = log_transf_perc_meth) )

overlap_grouped_log_WGBS <- overlap_grouped_log %>% 
  map(~ dplyr::filter(., seq_method=='WGBS')%>% 
        pivot_wider(names_from = sample_ids, values_from = log_transf_perc_meth) )

overlap_grouped_log_WGBS_distribution <- overlap_grouped_log_WGBS %>% 
  map(~ c(t(dplyr::select(., -c("tiles", "condition", "seq_method")))))

#normalise and set column and rownames
overlap_grouped_log_targeted_normalised <- overlap_grouped_log_targeted %>% 
  map2(overlap_grouped_log_WGBS_distribution, ~normalize.quantiles.use.target(as.matrix(dplyr::select(.x, -c("tiles", "condition", "seq_method"))), .y, copy=TRUE) %>% 
         as_tibble() %>% 
         set_names(colnames(dplyr::select(.x, -c("tiles", "condition", "seq_method")))) %>% 
         add_column(tiles=.x[["tiles"]], .before=0))

#Join targeted and WGBS dataframes
overlap_grouped_log_normalised <- overlap_grouped_log_targeted_normalised %>% 
  map2(overlap_grouped_log_WGBS, ~.x %>% 
         full_join(.y[,-c(2:3)], by="tiles") %>% 
         column_to_rownames("tiles") %>% 
         as.matrix() )


batch <- metadata %>%  
  mutate(seq_method_binary = case_when(seq_method=="WGBS" ~ 0, seq_method=="targeted" ~ 1)) %>% 
  dplyr::select(sample_ids, seq_method_binary) %>%  deframe()

#Run combat function on values
overlap_grouped_log_normalised_combat<- overlap_grouped_log_normalised %>% map(~ sva::ComBat(dat=., batch=batch[colnames(.)])%>% 
                                                       as_tibble(rownames = "tiles") %>% 
                                                       pivot_longer(-c(tiles), names_to="sample_ids", values_to="log_transf_perc_meth" ) %>%    
                                                                            left_join(metadata, by="sample_ids") %>%    
                                                                            mutate(treatment=as.factor(treatment)))

PCAs on log transformed, quantile normalised and combat data seperate condition common tiles

# Plot PCAs per condition
overlap_grouped_log_normalised_combat_pca <- overlap_grouped_log_normalised_combat %>%
  map2(names(.), ~ dplyr::select(.x, tiles, log_transf_perc_meth, sample_ids, seq_method) %>%
    pivot_wider(names_from = tiles, values_from = log_transf_perc_meth) %>% 
    add_column(condition=.y) )


overlap_grouped_log_normalised_combat_plot_per_disease<- overlap_grouped_log_normalised_combat_pca %>%
  map2(names(.), ~ autoplot(prcomp(dplyr::select(.x, starts_with("chr"))), data = .x, colour = "seq_method") +
    labs(title = .y, colour="Sequencing \nmethod") +
    theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1))

#plot_grid(plotlist = overlap_grouped_log_normalised_combat_plot_per_disease, nrow = 2, ncol = 2, labels = "AUTO")
annotate_figure(ggarrange(plotlist =overlap_grouped_log_normalised_combat_plot_per_disease , nrow=2, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Log Transformed, Quantile Normalised and ComBat\nDM Tiles", face = "bold", size=16))

PCAs on log transformed, quantile normalised and combat data all diseases common tiles

PCAs on log transformed, quantile normalised and combat data seperate condition DM tiles

# Perform PCA per condition on DM tiles
overlap_DM_grouped_log_normalised_combat <- overlap_grouped_log_normalised_combat %>% map(~ tidyr::unite(., tiles, tiles, condition, sep = ".") %>%
  dplyr::filter(tiles %in% c(diff_meth_tiles)) %>%
  tidyr::separate(tiles, into = c("chrom", "start", "end", "condition"), sep = "\\.") %>%
  tidyr::unite(tiles, chrom, start, end, sep = "."))

overlap_DM_grouped_log_normalised_combat <- overlap_DM_grouped_log_normalised_combat[2:4]

overlap_DM_grouped_log_normalised_combat_pca <- overlap_DM_grouped_log_normalised_combat %>%
  map(~ dplyr::select(., tiles, log_transf_perc_meth, sample_ids, seq_method, condition) %>%
    pivot_wider(names_from = tiles, values_from = log_transf_perc_meth))

overlap_DM_grouped_log_normalised_combat_plot_seperate_diseases <- overlap_DM_grouped_log_normalised_combat_pca %>%
  map2(names(.), ~ autoplot(prcomp(dplyr::select(.x, starts_with("chr"))), data = .x, colour = "seq_method") +
    labs(title = .y,  colour="Sequencing \nmethod") +
    theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1))

annotate_figure(ggarrange(plotlist = overlap_DM_grouped_log_normalised_combat_plot_seperate_diseases , nrow=2, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Log Transformed, Quantile Normalised and ComBat\nDM Tiles", face = "bold", size=16))

Calculate log fold change for quantile normalised and combat transformed data scatterplot

calc_log_fold_change <- function(log_dataframe) {
  log_dataframe %>%
    group_by(tiles, seq_method, condition) %>%
    summarise_at(vars(log_transf_perc_meth), list(name = mean)) %>%
    dplyr::rename(mean = "name") %>%
    pivot_wider(values_from = mean, names_from = condition) %>%
    mutate(
      meth.diff_STEMI = STEMI - Control,
      meth.diff_NSTEMI = NSTEMI - Control,
      meth.diff_UA = UA - Control
    ) %>%
    dplyr::select(-c(Control, NSTEMI, STEMI, UA)) %>%
    dplyr::rename(STEMI = "meth.diff_STEMI", NSTEMI = "meth.diff_NSTEMI", UA = "meth.diff_UA") %>%
    pivot_longer(-c(tiles, seq_method),
      names_to = "condition",
      values_to = "log_fold_change"
    ) %>%
    pivot_wider(names_from = "seq_method", values_from = "log_fold_change") %>%
    dplyr::rename(log_fold_change_WGBS = "WGBS", log_fold_change_targeted = "targeted")
}

overlap_log_normalised_combat <- overlap_grouped_log_normalised_combat %>%
  bind_rows() %>%
  dplyr::select(-c(treatment_descr, treatment))

overlap_grouped_log_normalised_combat_log_fold_change <- overlap_grouped_log_normalised_combat %>%
  bind_rows() %>%
  dplyr::select(-c(treatment_descr, treatment)) %>%
  calc_log_fold_change()

data_for_scatterplot <- data_for_scatterplot %>%
  tidyr::unite(tiles, seqnames, start, end, group, sep = ".")

overlap_DM_grouped_log_normalised_combat_log_fold_change <- overlap_grouped_log_normalised_combat_log_fold_change %>%
  tidyr::unite(tiles, tiles, condition, sep = ".") %>%
  dplyr::filter(tiles %in% c(data_for_scatterplot$tiles)) %>%
  tidyr::separate(tiles, into = c("chrom", "start", "end", "condition"), sep = "\\.")

data_for_scatterplot <- data_for_scatterplot %>%
  tidyr::separate(tiles, into = c("seqnames", "start", "end", "group"), sep = "\\.")

# Plot
p39 <- overlap_DM_grouped_log_normalised_combat_log_fold_change %>% ggplot(aes(x = log_fold_change_targeted, y = log_fold_change_WGBS)) +
  geom_point(colour = "#7CAE00", shape = 16, size=2, alpha=0.6) +
  ylab("log fold change WGBS") +
  xlab("log fold change Targeted Sequencing") +
  ylim(-5, 5) +
  labs(title = "Quantile Normalisation and ComBat") +
  stat_cor(method="pearson")+
  theme(plot.title = element_text(hjust = 0.5,  face="bold"), aspect.ratio = 1) +
  facet_grid(cols = vars(condition))

annotate_figure(ggarrange(p39 , nrow=1, ncol=1), text_grob("DM Tiles", face = "bold", size=16))

Backtransformation of Quantile Normalised and Combat Data

e_fun <- function(observed) {
  result <- ((exp(observed) * 100) / (1 + exp(observed)))
}

overlap_log_normalised_combat <- overlap_log_normalised_combat %>%
  dplyr::select(-c("seq_method", "condition")) %>%
  pivot_wider(names_from = sample_ids, values_from = log_transf_perc_meth)

overlap_log_normalised_combat_no_log <- overlap_log_normalised_combat %>%
  dplyr::select_if(is.numeric) %>%
  mutate_all(list(perc_meth = ~ e_fun(.))) %>%
  inner_join(overlap_log_normalised_combat) %>%
  dplyr::select(-c(1:40)) %>%
  relocate("tiles") %>%
  pivot_longer(-tiles, names_to = "sample_ids", values_to = "perc_meth") %>%
  mutate(across("sample_ids", str_replace, "_perc_meth", "")) %>%
  left_join(metadata %>% dplyr::select(sample_ids, condition, seq_method), by = "sample_ids")
Joining, by = c("SK", "VF", "N1", "N2", "N3", "N4", "N5", "N6", "H26", "H28", "2019", "2033", "3131", "AC7", "AC8", "AC9", "AC10", "AC11", "AC12", "AC13", "2017", "2018", "3052", "3158",
"AC1", "AC2", "AC3", "AC4", "AC5", "AC6", "AC14", "AC15", "2026", "2027", "AP1", "AP2", "AP3", "AP4", "AP5", "AP6")

Plot %Methylation per condition group

p40 <- overlap_log_normalised_combat_no_log %>% ggplot(aes(x = condition, y = perc_meth, fill = seq_method)) +
  geom_boxplot() +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5, face="bold"))

p41 <- overlap_log_normalised_combat_no_log %>% ggplot(aes(x = condition, y = perc_meth, fill = seq_method)) +
  geom_violin() +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5, face="bold"))

p42 <- overlap_log_normalised_combat_no_log %>% ggplot(aes(x = condition, y = perc_meth)) +
  geom_violin(aes(fill = seq_method)) +
  geom_boxplot(aes(fill = seq_method), width = 0.05) +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5, face="bold")) +
  facet_grid(seq_method ~ .)

p43 <- overlap_log_normalised_combat_no_log %>% ggplot(aes(x = condition, y = perc_meth)) +
  geom_violin(fill = "#7C7CFF") +
  ylab("Methylation [%]") +
  xlab("ACS Type") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5, face="bold"))

annotate_figure(ggarrange(p40, p41, p42, p43 , nrow=2, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Log-Backtransformed, Quantile Normalised and ComBat\nAll Common Tiles", face = "bold", size=16))

Plot %Methylation per sample

p44 <- overlap_log_normalised_combat_no_log %>%
  filter(seq_method == "WGBS") %>%
  ggplot(aes(x = sample_ids, y = perc_meth)) +
  geom_violin(fill = "#F8766D") +
  geom_boxplot(width = 0.05) +
  ylab("Methylation [%]") +
  xlab("Sample") +
  labs(title = "WGBS") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5, face="bold"))

p45 <- overlap_log_normalised_combat_no_log %>%
  filter(seq_method == "targeted") %>%
  ggplot(aes(x = sample_ids, y = perc_meth)) +
  geom_violin(fill = "#00BFC4") +
  geom_boxplot(width = 0.05) +
  ylab("Methylation [%]") +
  xlab("Sample") +
  labs(title = "Targeted Sequencing") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5, face="bold"))

p46 <- overlap_log_normalised_combat_no_log %>% ggplot(aes(x = sample_ids, y = perc_meth, fill = seq_method)) +
  geom_violin() +
  geom_boxplot(width = 0.05) +
  ylab("Methylation [%]") +
  xlab("Sample") +
  labs(title = "Log-Backtransformed, Quantile Normalised and ComBat\nAll Common Tiles") +
  scale_fill_discrete(name = "Method") +
  theme(plot.title = element_text(hjust = 0.5, face="bold"), axis.text.x = element_text(angle = 45, vjust = 0.8, hjust = 1))

annotate_figure(ggarrange(p44, p45, nrow=2, ncol=1, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Log-Backtransformed, Quantile Normalised and ComBat\nAll Common Tiles", face = "bold", size=16))

p46

overlap_log_normalised_combat_no_log_plot <- overlap_log_normalised_combat_no_log %>%
    pivot_wider(names_from = tiles, values_from = perc_meth)

p56 <- overlap_log_normalised_combat_no_log_plot %>%
  autoplot(prcomp(dplyr::select(., starts_with("chr"))), data = ., colour = "condition") +
  labs(colour="Condition") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"), aspect.ratio = 1)

p57 <- overlap_log_normalised_combat_no_log_plot %>%
  autoplot(prcomp(dplyr::select(., starts_with("chr"))), data = ., colour = "seq_method") +
  labs(colour="Sequencing \nmethod") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"), aspect.ratio = 1)

p58 <- overlap_log_normalised_combat_no_log_plot %>%
  autoplot(prcomp(dplyr::select(., starts_with("chr"))), data = ., shape = "seq_method", colour="condition") +
  labs(title = "Backtransformed, Quantile Normalised and ComBat\nAll Common Tiles", shape="Sequencing \nmethod", colour="Condition") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"), aspect.ratio = 1)

annotate_figure(ggarrange(p56, p57 , nrow=1, ncol=2, labels="AUTO"), text_grob("Backtransformed, Quantile Normalised and ComBat\nAll Common Tiles", face = "bold", size=16))


p58

# Perform PCA per condition on DM tiles
overlap_grouped_log_normalised_combat_log_fold_change_no_log <- overlap_log_normalised_combat_no_log %>% 
  group_by(condition) %>% 
  group_split()

overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log <- overlap_grouped_log_normalised_combat_log_fold_change_no_log %>% 
  map(~ tidyr::unite(., tiles, tiles, condition, sep = ".") %>%
  dplyr::filter(tiles %in% c(diff_meth_tiles)) %>%
  tidyr::separate(tiles, into = c("chrom", "start", "end", "condition"), sep = "\\.") %>%
  tidyr::unite(tiles, chrom, start, end, sep = "."))

overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log <- overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log[2:4]

overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log_pca <- overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log %>%
  map(~ dplyr::select(., tiles, perc_meth, sample_ids, seq_method, condition) %>%
    pivot_wider(names_from = tiles, values_from = perc_meth))

names(overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log_pca) <- c("NSTEMI", "STEMI", "UA")

overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log_plot_seperate_diseases <- overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log_pca %>%
  map2(names(.), ~ autoplot(prcomp(dplyr::select(.x, starts_with("chr"))), data = .x, colour = "seq_method") +
    labs(title = .y,  colour="Sequencing \nmethod") +
    theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1))

annotate_figure(ggarrange(plotlist = overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log_plot_seperate_diseases , nrow=2, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Backtransformed, Quantile Normalised and ComBat\nDM Tiles", face = "bold", size=16))


DM_tiles_NSTEMI <- overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log_pca[["NSTEMI"]] %>% dplyr::select(starts_with("chr")) %>% colnames()
DM_tiles_STEMI <- overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log_pca[["STEMI"]] %>% dplyr::select(starts_with("chr")) %>% colnames()
DM_tiles_UA <- overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log_pca[["UA"]] %>% dplyr::select(starts_with("chr")) %>% colnames()

DM_tiles_NSTEMI_unique <- setdiff(DM_tiles_NSTEMI, DM_tiles_STEMI)
DM_tiles_NSTEMI_unique <- setdiff(DM_tiles_NSTEMI_unique, DM_tiles_UA)


DM_tiles_STEMI_unique <- setdiff(DM_tiles_STEMI, DM_tiles_NSTEMI)
DM_tiles_STEMI_unique <- setdiff(DM_tiles_STEMI_unique, DM_tiles_UA)

DM_tiles_UA_unique <- setdiff(DM_tiles_UA, DM_tiles_NSTEMI)
DM_tiles_UA_unique <- setdiff(DM_tiles_UA_unique, DM_tiles_STEMI)

length(DM_tiles_NSTEMI_unique) #187
[1] 187
length(DM_tiles_STEMI_unique) #431
[1] 431
length(DM_tiles_UA_unique) #473
[1] 473
overlap_grouped_unique_DM_log_normalised_combat_log_fold_change_no_log_pca <- list()

overlap_grouped_unique_DM_log_normalised_combat_log_fold_change_no_log_pca[["NSTEMI"]] <- overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log_pca[["NSTEMI"]] %>% 
  dplyr::select(sample_ids, seq_method, condition, DM_tiles_NSTEMI_unique)
Note: Using an external vector in selections is ambiguous.
i Use `all_of(DM_tiles_NSTEMI_unique)` instead of `DM_tiles_NSTEMI_unique` to silence this message.
i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
overlap_grouped_unique_DM_log_normalised_combat_log_fold_change_no_log_pca[["STEMI"]] <- overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log_pca[["STEMI"]] %>% 
  dplyr::select(sample_ids, seq_method, condition, DM_tiles_STEMI_unique)
Note: Using an external vector in selections is ambiguous.
i Use `all_of(DM_tiles_STEMI_unique)` instead of `DM_tiles_STEMI_unique` to silence this message.
i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
overlap_grouped_unique_DM_log_normalised_combat_log_fold_change_no_log_pca[["UA"]] <- overlap_grouped_DM_log_normalised_combat_log_fold_change_no_log_pca[["UA"]] %>% 
  dplyr::select(sample_ids, seq_method, condition, DM_tiles_UA_unique)
Note: Using an external vector in selections is ambiguous.
i Use `all_of(DM_tiles_UA_unique)` instead of `DM_tiles_UA_unique` to silence this message.
i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
overlap_grouped_unique_DM_log_normalised_combat_log_fold_change_no_log_plot_seperate_diseases <- overlap_grouped_unique_DM_log_normalised_combat_log_fold_change_no_log_pca %>%
  map2(names(.), ~ autoplot(prcomp(dplyr::select(.x, starts_with("chr"))), data = .x, colour = "seq_method") +
    labs(title = .y,  colour="Sequencing \nmethod") +
    theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1))

annotate_figure(ggarrange(plotlist = overlap_grouped_unique_DM_log_normalised_combat_log_fold_change_no_log_plot_seperate_diseases , nrow=2, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Backtransformed, Quantile Normalised and ComBat\nUnique DM Tiles", face = "bold", size=16))

unique_DM_tiles <- c(unlist(DM_tiles_NSTEMI_unique), unlist(DM_tiles_STEMI_unique), unlist(DM_tiles_UA_unique))

#Filter methylation values for all per disease uniquely differentially methylated tiles
unique_DM_perc_meth <- overlap_log_normalised_combat_no_log %>% dplyr::filter(tiles %in% unique_DM_tiles)

unique_DM_perc_meth_pca <- unique_DM_perc_meth %>%  
  tidyr::pivot_wider(values_from=perc_meth, names_from=tiles)

p63 <- unique_DM_perc_meth_pca %>%
  autoplot(prcomp(dplyr::select(., starts_with("chr"))), data = ., colour = "condition") +
  labs(colour="Condition") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"), aspect.ratio = 1)

p64 <- unique_DM_perc_meth_pca %>%
  autoplot(prcomp(dplyr::select(., starts_with("chr"))), data = ., colour = "seq_method") +
  labs(colour="Sequencing \nmethod") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"), aspect.ratio = 1)

p65 <- unique_DM_perc_meth_pca %>%
  autoplot(prcomp(dplyr::select(., starts_with("chr"))), data = ., shape = "seq_method", colour="condition") +
  labs(title = "Backtransformed, Quantile Normalised and ComBat\nAll unique DM Tiles", shape="Sequencing \nmethod", colour="Condition") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"), aspect.ratio = 1)

annotate_figure(ggarrange(p63, p64 , nrow=1, ncol=2, labels="AUTO"), text_grob("Backtransformed, Quantile Normalised and ComBat\nAll unique DM Tiles", face = "bold", size=16))


p65

Compare difference of means per condition scatterplot and boxplot DM

calc_diff_of_means <- function(dataframe_all_samples, tiles.condition) {
  dataframe_all_samples_mean <- dataframe_all_samples %>%
    group_by(tiles, seq_method, condition) %>%
    summarise_at(vars(perc_meth), list(name = mean)) %>%
    dplyr::rename(mean = "name")

  dataframe_all_samples_mean_diff <- dataframe_all_samples_mean %>%
    pivot_wider(values_from = mean, names_from = condition) %>%
    mutate(
      meth.diff_STEMI = STEMI - Control,
      meth.diff_NSTEMI = NSTEMI - Control,
      meth.diff_UA = UA - Control
    ) %>%
    dplyr::select(-c(Control, NSTEMI, STEMI, UA)) %>%
    dplyr::rename(STEMI = "meth.diff_STEMI", NSTEMI = "meth.diff_NSTEMI", UA = "meth.diff_UA") %>%
    pivot_longer(-c(tiles, seq_method),
      names_to = "condition",
      values_to = "meth_diff"
    ) %>%
    pivot_wider(names_from = "seq_method", values_from = "meth_diff") %>%
    dplyr::rename(meth.diff.WGBS = "WGBS", meth.diff.targeted = "targeted")

  dataframe_all_samples_mean_diff_tiles <- dataframe_all_samples_mean_diff %>%
    tidyr::unite(tiles, tiles, condition, sep = ".") %>%
    filter(tiles %in% c(tiles.condition)) %>%
    tidyr::separate(tiles, into = c("chrom", "start", "end", "condition"), sep = "\\.")
}

overlap_DM_log_normalised_combat_log_fold_change_no_log_mean_diff <- calc_diff_of_means(overlap_log_normalised_combat_no_log, diff_meth_tiles)

#Calculate threshold for scatterplot
overlap_DM_log_normalised_combat_log_fold_change_no_log_mean_diff <- overlap_DM_log_normalised_combat_log_fold_change_no_log_mean_diff %>% 
  mutate(threshold_25= case_when((((25 <= meth.diff.WGBS) & (25 <= meth.diff.targeted))  | (((meth.diff.WGBS <=-25) & (meth.diff.targeted <=-25))) ) ~ "|25%|", TRUE ~ "not in range"))

p47 <- overlap_DM_log_normalised_combat_log_fold_change_no_log_mean_diff %>% 
  ggplot(aes(x = meth.diff.targeted, y = meth.diff.WGBS, colour=threshold_25)) +
  geom_point(shape = 16, size=2, alpha=0.6) +
    geom_vline(xintercept = c(-25, 25), linetype="dotted")+
  geom_hline(yintercept = c(-25, 25), linetype="dotted")+
  ylab("Mean Methylation Difference WGBS") +
  xlab("Mean Methylation Difference Targeted Sequencing") +
  labs(title = "Log-Backtransformed, Quantile Normalised and ComBat", colour="Threshold") +
  stat_cor(method="pearson")+
  ylim(-70, 70) +
  xlim(-70, 70) +
  theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1) +
  scale_color_manual(values=c("#919494", "#7CAE00"))+
  facet_grid(cols = vars(condition))

annotate_figure(ggarrange(p47 , nrow=1, ncol=1), text_grob("DM Tiles", face = "bold", size=16))


# Plot distribution of mean DM per condition boxplots
p48 <- overlap_DM_log_normalised_combat_log_fold_change_no_log_mean_diff %>% ggplot(aes(x = condition, y = meth.diff.targeted, fill = condition)) +
  geom_boxplot() +
  ylab("Mean Methylation Difference [%]") +
  xlab("ACS Type") +
  labs(title = "Targeted Sequencing") +
  scale_fill_discrete(name = "ACS Type") +
  theme(plot.title = element_text(hjust = 0.5)) +
  ylim(-100, 80)

p49 <- overlap_DM_log_normalised_combat_log_fold_change_no_log_mean_diff %>% ggplot(aes(x = condition, y = meth.diff.WGBS, fill = condition)) +
  geom_boxplot() +
  ylab("Mean Methylation Difference [%]") +
  xlab("ACS Type") +
  labs(title = "WGBS") +
  scale_fill_discrete(name = "ACS Type") +
  ylim(-100, 80) +
  theme(plot.title = element_text(hjust = 0.5))

annotate_figure(ggarrange(p48, p49 , nrow=1, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Log-Backtransformed, Quantile Normalised and ComBat\nDM Tiles", face = "bold", size=16))

#Add qvalue to dataframe and calculate if threshold for qvalue below 0.01
lim=65

overlap_DM_log_normalised_combat_log_fold_change_no_log_mean_diff_qvalues <- overlap_DM_log_normalised_combat_log_fold_change_no_log_mean_diff %>% 
  tidyr::unite(tiles, chrom, start, end, condition, sep=".") %>% 
  left_join(dplyr::select(bind_rows(methylDiff_validation), tiles, qvalue), by="tiles") %>% 
  dplyr::rename(qvalue_targeted= qvalue) %>% 
  left_join(dplyr::select(bind_rows(methylDiff_WGBS), tiles, qvalue), by="tiles") %>% 
  dplyr::rename(qvalue_WGBS=qvalue) %>% 
  tidyr::separate(tiles, into=c("chrom", "start", "end", "condition")) %>% 
  dplyr::mutate(threshold_25_qvalue= case_when(threshold_25 =="|25%|" & qvalue_targeted <=0.01 & qvalue_WGBS <=0.01 ~ "significant", TRUE ~ "insignificant"))            

p59 <- overlap_DM_log_normalised_combat_log_fold_change_no_log_mean_diff_qvalues %>% 
  ggplot(aes(x = meth.diff.targeted, y = meth.diff.WGBS, colour=threshold_25_qvalue)) +
  geom_point(shape = 16, alpha=0.6, size=2) +
    geom_vline(xintercept = c(-25, 25), linetype="dotted")+
  geom_hline(yintercept = c(-25, 25), linetype="dotted")+
  ylab("Mean Methylation Difference WGBS") +
  xlab("Mean Methylation Difference Targeted Sequencing") +
  labs(title = "Log-Backtransformed, Quantile Normalised and ComBat", colour="Threshold") +
  stat_cor(method="pearson")+
  ylim(-lim, lim) +
  xlim(-lim, lim) +
  theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1) +
  scale_color_manual(values=c("#919494", "#7CAE00"))+
  facet_grid(cols = vars(condition))

annotate_figure(ggarrange(p59 , nrow=1, ncol=1), text_grob("DM Tiles", face = "bold", size=16))

Union of all DM tiles

#Get all tiles of differential methylation regardless of percentage
all_DM_tiles<- overlap_DM_log_normalised_combat_log_fold_change_no_log_mean_diff_qvalues %>%  
  #filter(threshold_25 == "|25%|") %>% 
  tidyr::unite(tiles, chrom, start, end, sep=".") %>% 
  pull(tiles) %>% 
  unique()

#Filter methylation values for all differentially methylated tiles
all_DM_perc_meth <- overlap_log_normalised_combat_no_log %>% dplyr::filter(tiles %in% all_DM_tiles)

all_DM_perc_meth_pca <- all_DM_perc_meth %>%  
  tidyr::pivot_wider(values_from=perc_meth, names_from=tiles)

p60 <- all_DM_perc_meth_pca %>%
  autoplot(prcomp(dplyr::select(., starts_with("chr"))), data = ., colour = "condition") +
  labs(colour="Condition") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"), aspect.ratio = 1)

p61 <- all_DM_perc_meth_pca %>%
  autoplot(prcomp(dplyr::select(., starts_with("chr"))), data = ., colour = "seq_method") +
  labs(colour="Sequencing \nmethod") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"), aspect.ratio = 1)

p62 <- all_DM_perc_meth_pca %>%
  autoplot(prcomp(dplyr::select(., starts_with("chr"))), data = ., shape = "seq_method", colour="condition") +
  labs(title = "Backtransformed, Quantile Normalised and ComBat\nAll DM Tiles", shape="Sequencing \nmethod", colour="Condition") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"), aspect.ratio = 1)

annotate_figure(ggarrange(p60, p61 , nrow=1, ncol=2, labels="AUTO"), text_grob("Backtransformed, Quantile Normalised and ComBat\nAll DM Tiles", face = "bold", size=16))


p62


#Alternative method
# test<- reduce(group_split(all_DM_perc_meth, condition), inner_join, by=tiles)

DMRs between conditions

Compare Validation Cohort Tiles to Discovery Cohort Tiles

p66
Warning: Removed 3 rows containing non-finite values (stat_cor).
Warning: Removed 3 rows containing missing values (geom_point).

cohort_comparison_validation_numbers_q_value_directional <- compare_discovery_validation %>%
  group_by(condition) %>% 
  dplyr::count(threshold_qvalue_directional =="significant") %>% 
  dplyr::rename(threshold_q_value_directional=2) %>% 
  pivot_wider(names_from=threshold_q_value_directional, values_from=n) %>% 
  dplyr::rename(Significant_DMR=3, Insignificant_DMR=2) %>% 
  mutate(Percentage_Significant_DMR=(Significant_DMR/(Insignificant_DMR+Significant_DMR)*100), 
         Total_Number_DMRs=sum(Significant_DMR, Insignificant_DMR)) %>% 
  dplyr::relocate(Total_Number_DMRs, .after=condition)

cohort_comparison_validation_numbers_q_value_25_cutoff <- compare_discovery_validation %>%
  dplyr::filter(threshold_qvalue == "significant") %>% 
  group_by(condition) %>%
  dplyr::count(threshold_25_cohort_comparison == "DMR validated" & threshold_qvalue == "significant") %>% 
  dplyr::rename(threshold_25=2) %>% 
  pivot_wider(names_from=threshold_25, values_from=n) %>%
  dplyr::rename(Significant_DMR_Validated=3, Significant_DMR_Not_Validated=2) %>%
  mutate(Percentage_Significant_DMR_Validated=(Significant_DMR_Validated/(Significant_DMR_Not_Validated+Significant_DMR_Validated)*100), 
         Total_Number_DMRs=sum(Significant_DMR_Not_Validated, Significant_DMR_Validated)) %>% 
  dplyr::relocate(Total_Number_DMRs, .after=condition)

cohort_comparison_validation_numbers_q_value_directional_25_cutoff <- compare_discovery_validation %>%
  dplyr::filter(threshold_qvalue_directional == "significant") %>% 
  group_by(condition) %>%
  dplyr::count(threshold_25_cohort_comparison == "DMR validated" & threshold_qvalue == "significant") %>% 
  dplyr::rename(threshold_25=2) %>% 
  pivot_wider(names_from=threshold_25, values_from=n) %>%
  dplyr::rename(Significant_DMR_Validated=3, Significant_DMR_Not_Validated=2) %>%
  mutate(Percentage_Significant_DMR_Validated=(Significant_DMR_Validated/(Significant_DMR_Not_Validated+Significant_DMR_Validated)*100), 
         Total_Number_DMRs=sum(Significant_DMR_Not_Validated, Significant_DMR_Validated)) %>% 
  dplyr::relocate(Total_Number_DMRs, .after=condition)


print(cohort_comparison_validation_numbers_q_value_directional)
print(cohort_comparison_validation_numbers_q_value_25_cutoff)
print(cohort_comparison_validation_numbers_q_value_directional_25_cutoff)

Correlate Validated DMRs to Clinical Markers

To find out if DMR validation might be associable with clinical marker expression

#First try to use quantile and combat normalised perc_meth values:


DMRs <- compare_discovery_validation %>% 
  dplyr::select(chrom, start, end, condition, threshold_25_cohort_comparison) %>% 
  tidyr::unite(DMR, chrom, start, end, sep=".") %>% 
  group_split(threshold_25_cohort_comparison) %>% 
  map(~pull(., DMR) %>% unique())

#Join with clinical Data
overlap_log_normalised_combat_no_log_plot_clinical_data<-overlap_log_normalised_combat_no_log_plot %>% 
  dplyr::select(sample_ids, starts_with("chr")) %>% 
  dplyr::inner_join(clinical_markers_ACS, by = c("sample_ids"="Sample"))

#Calculate Correlation
validation_corr_biomarkers <- overlap_log_normalised_combat_no_log_plot_clinical_data %>% 
  dplyr::select(any_of(c(DMRs[[1]], DMRs[[2]])), "LVEF(%)", "CRP(mg/dl_<5)","TroponinThs_t1 (ng/l <14or<50)", "CK (U/l _<190)" , "CKmax(U/l_<190)" ,"CK-MB(U/l <24)","CK-MB_Max") %>% 
  stats::cor(use = "complete.obs",method = "pearson") %>%
  as_tibble(rownames="DMR") %>% 
  dplyr::mutate(across(where(is.numeric), ~.^2)) %>% 
  dplyr::select(DMR, "LVEF(%)", "CRP(mg/dl_<5)","TroponinThs_t1 (ng/l <14or<50)", "CK (U/l _<190)" , "CKmax(U/l_<190)" ,"CK-MB(U/l <24)","CK-MB_Max")

#Annotate with validation status
validation_corr_biomarkers <- validation_corr_biomarkers %>% 
  dplyr::mutate(DMRs_validation=if_else(DMR %in% DMRs[[2]], "validated", "not validated"))

validation_corr_biomarkers_long <- validation_corr_biomarkers %>%
  dplyr::rename('CRP (mg/dl)'= "CRP(mg/dl_<5)", 
                'TroponinT (ng/l)'="TroponinThs_t1 (ng/l <14or<50)",
                'CK (U/l)'="CK (U/l _<190)",
                'CK max (U/l)'="CKmax(U/l_<190)",
                'CK-MB (U/l)'="CK-MB(U/l <24)",
                'CK-MB max (U/l)'="CK-MB_Max") %>% 
  tidyr::pivot_longer(-c(DMR, DMRs_validation), names_to = "biomarker", values_to="Rsquared")

#Plot
clinical_marker_correlation <- validation_corr_biomarkers_long %>% 
  ggplot(aes(x = DMRs_validation, y = Rsquared, fill=DMRs_validation)) +
  geom_boxplot(outlier.size=0.3) +
  ggpubr::stat_compare_means(size=2, label.x=1.2, label.y=1.1)+  
  labs(y=expression("R"^2), x="DMRs") +
  ylim(0,1.25)+
  scale_fill_manual(name= "DMRs", values=c("darkred", "darkgreen")) +
  theme_bw()+
  facet_wrap(vars(biomarker))+
  theme(strip.text = element_text(size = 6), axis.text=element_text(size=6))

clinical_marker_correlation


# ggsave(bg ="white",
# "/home/arathge/output/plots/ACSS_cardiac_ccfDNA/clinical_marker_correlation.tiff",
# device = "tiff",
# plot = clinical_marker_correlation
# )
# Try also with unnormalised raw perc_meth values:

#Transpose tibble
overlap_tiles_validation_WGBS_t <- overlap_tiles_validation_WGBS %>% 
  pivot_longer(-tiles) %>%   
  pivot_wider(names_from = tiles, values_from = value) %>% 
  dplyr::rename(sample_ids="name")

#Join with Clinical Data
overlap_tiles_validation_WGBS_t_clinical_data<-overlap_tiles_validation_WGBS_t %>% 
  dplyr::select(sample_ids, starts_with("chr")) %>% 
  dplyr::inner_join(clinical_markers_ACS, by = c("sample_ids"="Sample"))

#Calculate Correlation
validation_corr_biomarkers_raw_data <- overlap_tiles_validation_WGBS_t_clinical_data %>% 
  dplyr::select(any_of(c(DMRs[[1]], DMRs[[2]])), "LVEF(%)", "CRP(mg/dl_<5)","TroponinThs_t1 (ng/l <14or<50)", "CK (U/l _<190)" , "CKmax(U/l_<190)" ,"CK-MB(U/l <24)","CK-MB_Max") %>% 
  stats::cor(use = "complete.obs",method = "pearson") %>%
  as_tibble(rownames="DMR") %>% 
  dplyr::mutate(across(where(is.numeric), ~.^2)) %>% 
  dplyr::select(DMR, "LVEF(%)", "CRP(mg/dl_<5)","TroponinThs_t1 (ng/l <14or<50)", "CK (U/l _<190)" , "CKmax(U/l_<190)" ,"CK-MB(U/l <24)","CK-MB_Max")

#Annotate with validation status
validation_corr_biomarkers_raw_data <- validation_corr_biomarkers_raw_data %>% 
  dplyr::mutate(DMRs_validation=if_else(DMR %in% DMRs[[2]], "validated", "not validated"))

validation_corr_biomarkers_raw_data_long <- validation_corr_biomarkers_raw_data %>%
  dplyr::rename('CRP (mg/dl)'= "CRP(mg/dl_<5)", 
                'TroponinT (ng/l)'="TroponinThs_t1 (ng/l <14or<50)",
                'CK (U/l)'="CK (U/l _<190)",
                'CK max (U/l)'="CKmax(U/l_<190)",
                'CK-MB (U/l)'="CK-MB(U/l <24)",
                'CK-MB max (U/l)'="CK-MB_Max") %>% 
  tidyr::pivot_longer(-c(DMR, DMRs_validation), names_to = "biomarker", values_to="Rsquared")

#Plot
clinical_marker_correlation_raw_data <- validation_corr_biomarkers_raw_data_long %>% 
  ggplot(aes(x = DMRs_validation, y = Rsquared, fill=DMRs_validation)) +
  geom_boxplot(outlier.size=0.3) +
  ggpubr::stat_compare_means(size=2, label.x=1.2, label.y=1.1)+  
  labs(y=expression("R"^2), x="DMRs") +
  ylim(0,1.25)+
  scale_fill_manual(name= "DMRs", values=c("darkred", "darkgreen")) +
  theme_bw()+
  facet_wrap(vars(biomarker))+
  theme(strip.text = element_text(size = 6), axis.text=element_text(size=6))

clinical_marker_correlation_raw_data


# ggsave(bg ="white",
# "/home/arathge/output/plots/ACSS_cardiac_ccfDNA/clinical_marker_correlation_raw_data.tiff",
# device = "tiff",
# plot = clinical_marker_correlation_raw_data
# )

Coverage weighted %Methylation for ComBat with Quantile Normalisation

methCovPerBaseWGBS <- setNames(methylKit::getData(methylBaseDB_WGBS_all_samples)[, c(1, 2, 3, methylBaseDB_WGBS_all_samples@coverage.index)], c("chr", "start", "end", methylBaseDB_WGBS_all_samples@sample.ids))
Uncompressing file.
Reading file.
methCovPerBaseTargeted <- setNames(methylKit::getData(methylBaseDB_validation_no_CAD)[, c(1, 2, 3, methylBaseDB_validation_no_CAD@coverage.index)], c("chr", "start", "end", methylBaseDB_validation_no_CAD@sample.ids))
#detach("package:methylKit", unload = TRUE)
#detach("package:GenomicRanges", unload = TRUE)

methCovPerBaseWGBS <- methCovPerBaseWGBS %>%
  tidyr::unite(tiles, chr, start, end, sep = ".") %>%
  dplyr::filter(tiles %in% c(tiles))

methCovPerBaseTargeted <- methCovPerBaseTargeted %>%
  tidyr::unite(tiles, chr, start, end, sep = ".") %>%
  dplyr::filter(tiles %in% c(tiles))


methCovPerBase <- methCovPerBaseWGBS %>% inner_join(methCovPerBaseTargeted)
Joining, by = "tiles"
methCovPerBase <- methCovPerBase %>% pivot_longer(-tiles, names_to = "sample_ids", values_to = "coverage")

all_data_coverage <- all_data %>% left_join(methCovPerBase, by = c("tiles", "sample_ids"))
DM_data_coverage <- all_data_coverage %>%
  tidyr::unite(tiles, tiles, condition, sep = ".") %>%
  filter(tiles %in% diff_meth_tiles) %>%
  tidyr::separate(tiles, into = c("chrom", "start", "end", "condition"))
overlap_log_normalised_combat_no_log_weighted <- overlap_log_normalised_combat_no_log %>% left_join(dplyr::select(all_data_coverage, tiles, sample_ids, coverage), by = c("tiles", "sample_ids"))

calc_weighted_diff_of_means <- function(dataframe_all_samples) {
  dataframe_all_samples_mean <- dataframe_all_samples %>%
    dplyr::group_by(tiles, seq_method, condition) %>%
    dplyr::summarise(weighted_mean = weighted.mean(perc_meth, coverage))

  dataframe_all_samples_mean_diff <- dataframe_all_samples_mean %>%
    pivot_wider(values_from = weighted_mean, names_from = condition) %>%
    mutate(
      meth.diff_STEMI = STEMI - Control,
      meth.diff_NSTEMI = NSTEMI - Control,
      meth.diff_UA = UA - Control
    ) %>%
    dplyr::select(-c(Control, NSTEMI, STEMI, UA)) %>%
    dplyr::rename(STEMI = "meth.diff_STEMI", NSTEMI = "meth.diff_NSTEMI", UA = "meth.diff_UA") %>%
    pivot_longer(-c(tiles, seq_method),
      names_to = "condition",
      values_to = "weighted_meth_diff"
    ) %>%
    pivot_wider(names_from = "seq_method", values_from = "weighted_meth_diff") %>%
    dplyr::rename(weighted.meth.diff.WGBS = "WGBS", weighted.meth.diff.targeted = "targeted")
}

overlap_log_normalised_combat_no_log_weighted <- calc_weighted_diff_of_means(overlap_log_normalised_combat_no_log_weighted)
`summarise()` has grouped output by 'tiles', 'seq_method'. You can override using the `.groups` argument.
overlap_DM_log_normalised_combat_log_fold_change_no_log_weighted <- overlap_log_normalised_combat_no_log_weighted %>%
  tidyr::unite(tiles, tiles, condition, sep = ".") %>%
  dplyr::filter(tiles %in% c(diff_meth_tiles)) %>%
  tidyr::separate(tiles, into = c("chrom", "start", "end", "condition"), sep = "\\.") %>% 
  tidyr::unite(tiles, chrom, start, end, sep=".")
#Calculate threshold 
overlap_log_normalised_combat_no_log_weighted <- overlap_log_normalised_combat_no_log_weighted %>% 
  mutate(threshold_25= case_when((((25 <= weighted.meth.diff.WGBS) & (25 <= weighted.meth.diff.targeted))  | (((weighted.meth.diff.targeted <=-25) & (weighted.meth.diff.WGBS <=-25))) ) ~ "|25%|", TRUE ~ "not in range"))

overlap_DM_log_normalised_combat_log_fold_change_no_log_weighted <- overlap_DM_log_normalised_combat_log_fold_change_no_log_weighted %>% 
  mutate(threshold_25= case_when((((25 <= weighted.meth.diff.WGBS) & (25 <= weighted.meth.diff.targeted))  | (((weighted.meth.diff.targeted <=-25) & (weighted.meth.diff.WGBS <=-25))) ) ~ "|25%|", TRUE ~ "not in range"))

#Count how many tiles are above/below threshold for each condition
overlap_log_normalised_combat_no_log_weighted_validated <- overlap_log_normalised_combat_no_log_weighted %>% 
  dplyr::group_by(condition) %>% 
  dplyr::count(threshold_25 =="|25%|") %>% 
  dplyr::rename(threshold_25=2) %>% 
  pivot_wider(names_from=threshold_25, values_from=n) %>%
  dplyr::rename(Validated=3, Not_Validated=2) %>% 
  mutate(percentage=(Validated/(Not_Validated+Validated)*100))

print(overlap_log_normalised_combat_no_log_weighted_validated)

overlap_DM_log_normalised_combat_log_fold_change_no_log_weighted_validated <- overlap_DM_log_normalised_combat_log_fold_change_no_log_weighted %>%   
  dplyr::group_by(condition) %>% 
  dplyr::count(threshold_25 =="|25%|") %>% 
  dplyr::rename(threshold_25=2) %>% 
  pivot_wider(names_from=threshold_25, values_from=n) %>% 
  dplyr::rename(Validated=3, Not_Validated=2) %>% 
  mutate(percentage=(Validated/(Not_Validated+Validated)*100))

print(overlap_DM_log_normalised_combat_log_fold_change_no_log_weighted_validated)

p50 <- overlap_log_normalised_combat_no_log_weighted %>%
  ggplot(aes(x = weighted.meth.diff.targeted, y = weighted.meth.diff.WGBS, colour=threshold_25)) +
  geom_point(shape = 16, alpha=0.6, size=2) +
  geom_vline(xintercept = c(-25, 25), linetype="dotted")+
  geom_hline(yintercept = c(-25, 25), linetype="dotted")+
  ylab("Weighted Mean Methylation Difference WGBS") +
  xlab("Weighted Mean Methylation Difference Targeted Sequencing") +
  labs(title = "All Common Tiles", colour="Threshold") +
  stat_cor(method="pearson")+ 
  xlim(-90, 90) +
  ylim(-90, 90) +
  theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1) +
  scale_color_manual(values=c("#919494", "#7CAE00"))+
  facet_grid(cols = vars(condition))

p51 <- overlap_DM_log_normalised_combat_log_fold_change_no_log_weighted %>%
  ggplot(aes(x = weighted.meth.diff.targeted, y = weighted.meth.diff.WGBS, colour=threshold_25)) +
  geom_point(shape = 16, alpha=0.6, size=2) +
  geom_vline(xintercept = c(-25, 25), linetype="dotted")+
  geom_hline(yintercept = c(-25, 25), linetype="dotted")+
  ylab("Weighted Mean Methylation Difference WGBS") +
  xlab("Weighted Mean Methylation Difference Targeted Sequencing") +
  labs(title = "DM Tiles", colour="Threshold") +
  stat_cor(method="pearson")+ 
  xlim(-90, 90) +
  ylim(-90, 90) +
  theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1) +
  scale_color_manual(values=c("#919494", "#7CAE00"))+
  facet_grid(cols = vars(condition))

annotate_figure(ggarrange(p50, p51 , nrow=2, ncol=1, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("Log-Backtransformed, Quantile Normalised and ComBat", face = "bold", size=16))

#Add qvalue to dataframe and calculate if threshold for qvalue below 0.01
overlap_DM_log_normalised_combat_log_fold_change_no_log_weighted_qvalues <- overlap_DM_log_normalised_combat_log_fold_change_no_log_weighted %>% 
  tidyr::unite(tiles, tiles, condition, sep=".") %>% 
  left_join(dplyr::select(bind_rows(methylDiff_validation), tiles, qvalue)) %>% 
  dplyr::rename(qvalue_targeted=qvalue) %>% 
  left_join(dplyr::select(bind_rows(methylDiff_WGBS), tiles, qvalue)) %>% 
  dplyr::rename(qvalue_WGBS=qvalue) %>% 
  tidyr::separate(tiles, into=c("chrom", "start", "end", "condition")) %>% 
  dplyr::mutate(threshold_25_qvalue= case_when(threshold_25 =="|25%|" & qvalue_targeted <=0.01 & qvalue_WGBS <0.01 ~ "significant", TRUE ~ "insignificant")) 
Joining, by = "tiles"
Joining, by = "tiles"
p51 <- overlap_DM_log_normalised_combat_log_fold_change_no_log_weighted_qvalues %>%
  ggplot(aes(x = weighted.meth.diff.targeted, y = weighted.meth.diff.WGBS, colour=threshold_25_qvalue)) +
  geom_point(shape = 16, size=2, alpha=0.6) +
  geom_vline(xintercept = c(-25, 25), linetype="dotted")+
  geom_hline(yintercept = c(-25, 25), linetype="dotted")+
  ylab("Weighted Mean Methylation Difference WGBS") +
  xlab("Weighted Mean Methylation Difference Targeted Sequencing") +
  labs(title = "DM Tiles", colour="Threshold") +
  stat_cor(method="pearson")+ 
  xlim(-90, 90) +
  ylim(-90, 90) +
  theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1) +
  scale_color_manual(values=c("#919494", "#7CAE00"))+
  facet_grid(cols = vars(condition))

p51

ComBat without Quantile Normalisation

long_df_to_matrix <- function(df) {
  df %>%
    dplyr::select(1:3) %>%
    pivot_wider(names_from = sample_ids, values_from = log_transf_perc_meth) %>%
    column_to_rownames("tiles") %>%
    as.matrix() %>%
    return()
}


add_metadata_matrix <- function(mx, metadata_df) {
  mx %>%
    as_tibble(rownames = "tiles") %>%
    pivot_longer(-tiles, names_to = "sample_ids", values_to = "log_transf_perc_meth") %>%
    left_join(dplyr::select(metadata, sample_ids, seq_method, condition)) %>%
    pivot_wider(names_from = tiles, values_from = log_transf_perc_meth) %>%
    return()
}

PCA on log transformed and combat data seperate condition all common tiles

overlap_grouped_log_combat <- overlap_grouped_log %>%
  map(~ long_df_to_matrix(.) %>%
  sva::ComBat(dat = ., batch = batch[colnames(.)]) %>%  
    add_metadata_matrix(., metadata_df = metadata))
Found 165 genes with uniform expression within a single batch (all zeros); these will not be adjusted for batch.
Found2batches
Adjusting for0covariate(s) or covariate level(s)
Standardizing Data across genes
Fitting L/S model and finding priors
Finding parametric adjustments
Adjusting the Data
Joining, by = "sample_ids"
Found 119 genes with uniform expression within a single batch (all zeros); these will not be adjusted for batch.
Found2batches
Adjusting for0covariate(s) or covariate level(s)
Standardizing Data across genes
Fitting L/S model and finding priors
Finding parametric adjustments
Adjusting the Data
Joining, by = "sample_ids"
Found 54 genes with uniform expression within a single batch (all zeros); these will not be adjusted for batch.
Found2batches
Adjusting for0covariate(s) or covariate level(s)
Standardizing Data across genes
Fitting L/S model and finding priors
Finding parametric adjustments
Adjusting the Data
Joining, by = "sample_ids"
Found 191 genes with uniform expression within a single batch (all zeros); these will not be adjusted for batch.
Found2batches
Adjusting for0covariate(s) or covariate level(s)
Standardizing Data across genes
Fitting L/S model and finding priors
Finding parametric adjustments
Adjusting the Data
Joining, by = "sample_ids"
overlap_grouped_log_combat_pca_plot <- overlap_grouped_log_combat %>%
  map2(
    names(.),
    ~ autoplot(prcomp(dplyr::select(.x, starts_with("chr"))), data = .x, colour = "seq_method") +
      labs(title = .y, colour="Sequencing \nmethod") +
      theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1)
  )

annotate_figure(ggarrange(plotlist = overlap_grouped_log_combat_pca_plot , nrow=2, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("ComBat in Log Space\nAll Common Tiles", face = "bold", size=16))

PCA on log transformed and combat data all diseases all common tiles

overlap_log_combat <- overlap_log %>%
  long_df_to_matrix() %>%
  ComBat(dat = ., batch = batch[colnames(.)]) %>%
  add_metadata_matrix(metadata_df = metadata)
overlap_log_combat <- overlap_log %>%
  long_df_to_matrix() %>%
  ComBat(dat = ., batch = batch[colnames(.)]) %>%
  add_metadata_matrix(metadata_df = metadata)
Found 14 genes with uniform expression within a single batch (all zeros); these will not be adjusted for batch.
Found2batches
Adjusting for0covariate(s) or covariate level(s)
Standardizing Data across genes
Fitting L/S model and finding priors
Finding parametric adjustments
Adjusting the Data
Joining, by = "sample_ids"
overlap_DM_grouped_log_combat <-overlap_grouped_log_combat %>%
  map(~ pivot_longer(., -c(sample_ids, condition, seq_method), names_to = "tiles", values_to = "log_transf_perc_meth")%>%
  tidyr::unite(tiles, tiles, condition, sep=".") %>%
  dplyr::filter(tiles %in% c(diff_meth_tiles)) %>%
  tidyr::separate(tiles, into = c("chrom", "start", "end", "condition"), sep = "\\.") %>%
  tidyr::unite(tiles, chrom, start, end, sep=".") %>% 
  pivot_wider(names_from = tiles, values_from = log_transf_perc_meth))

overlap_DM_grouped_log_combat<-overlap_DM_grouped_log_combat[2:4]
overlap_DM_grouped_log_combat_pca_plot <- overlap_DM_grouped_log_combat%>%
  map2(
    names(.),
    ~ autoplot(prcomp(dplyr::select(.x, starts_with("chr"))), data = .x, colour = "seq_method") +
      labs(title = .y, colour="Sequencing \nmethod") +
      theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1)
  )

annotate_figure(ggarrange(plotlist = overlap_DM_grouped_log_combat_pca_plot , nrow=2, ncol=2, labels="AUTO", common.legend = TRUE, legend="right"), text_grob("ComBat in Log Space\nDM Tiles", face = "bold", size=16))

Calculate log fold change for comBat data scatterplot


overlap_log_combat_log_fold_change <- overlap_log %>% calc_log_fold_change()

overlap_DM_log_combat_log_fold_change <- overlap_log_combat_log_fold_change %>%
  tidyr::unite(tiles, tiles, condition, sep = ".") %>%
  dplyr::filter(tiles %in% c(diff_meth_tiles)) %>%
  tidyr::separate(tiles, into = c("chrom", "start", "end", "condition"), sep = "\\.")

# Plot
p38 <- overlap_DM_log_combat_log_fold_change %>% ggplot(aes(x = log_fold_change_targeted, y = log_fold_change_WGBS)) +
  geom_point(colour = "#7CAE00", shape = 16, size=2, alpha=0.6) +
  ylab("log fold change WGBS") +
  xlab("log fold change Targeted Sequencing") +
  labs(title = "ComBat in Log Space\nAll Common Tiles") +
  stat_cor(method="pearson")+  
  ylim(-5, 5) +
  xlim(-5, +5) +
  theme(plot.title = element_text(hjust = 0.5, face="bold"), aspect.ratio = 1) +
  facet_grid(cols = vars(condition))

p38

Overview Plot: PCA Grid all common tiles

data <- list("Log" = overlap_grouped_log_pca, "ComBat"=overlap_grouped_log_combat, "Quantile Normalisation \n+ ComBat" = overlap_grouped_log_normalised_combat_pca) %>%
  map(bind_rows, .id = "condition2") %>%
  map(~ bind_cols(
    dplyr::select(.x, !starts_with("chr")), prcomp(dplyr::select(.x, starts_with("chr")))$x
  )) %>%
  bind_rows(.id = "normalization") %>%
  mutate(normalization = factor(normalization, levels = c( "Log", "ComBat", "Quantile Normalisation \n+ ComBat")))

ggplot(data, aes(PC1, PC2, colour = condition, shape=seq_method)) +
  geom_point(size=2) +
  facet_grid(normalization ~ condition2, margins = "condition2", scales = "free") +
  labs(shape="Sequencing method", colour = "Condition" ) +
  theme_bw() +
  theme(aspect.ratio = 1)+
  scale_x_continuous(sec.axis = sec_axis(~ . , name = "All Common Tiles", breaks = NULL, labels = NULL))

Make Publication Figures

ggsave(bg ="white",
"/local/AAkalin_cardiac/Results/cardiac/Plots/FigureS5.pdf",
device = "pdf",
plot = figureS5
)
Saving 7 x 7 in image
LS0tCnRpdGxlOiAiVGFyZ2V0ZWRfU2VxX05vcm1hbGlzYXRpb25fYW5kX0RNUl9WYWxpZGF0aW9uIgphdXRob3I6ICJBbmphIFJhdGhnZWJlciIKZGF0ZTogIjE3LkF1Z3VzdC4yMDIyIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvY19kZXB0aDogNAogICAgdG9jX2Zsb2F0OiB0cnVlCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KIyBHT0FMClRoZSBhaW0gb2YgdGhpcyBzY3JpcHQgaXMgdG8gY29tcGFyZSBpZiB0aGVyZSBpcyBhIHN5c3RlbWljIGJpYXMgYmV0d2VlbiBXR0JTIHByb2Nlc3NlZCBzYW1wbGVzIGFuZCB0YXJnZXRlZCBzZXF1ZW5jZWQgc2FtcGxlcyBhbmQgdG8gcmVtb3ZlIGl0LgpBbHNvLCB0aGUgdGFyZ2V0ZWQgc2VxdWVuY2luZyBkYXRhIGZ1bmN0aW9ucyBhcyB2YWxpZGF0aW9uIGNvaG9ydCBmb3IgdGhlIERNUnMgaWRlbnRpZmllZCBmcm9tIHRoZSBkaXNjb3ZlcnkgY29ob3J0LgoKIyBDb25jbHVzaW9uClRoZSBzZXF1ZW5jaW5nIGJpYXMgY291bGQgYmVzdCBiZSByZW1vdmVkIGJ5IGNvbWJpbmluZyBhIHF1YW50aWxlIG5vcm1hbGlzYXRpb24gd2l0aCBhIENvbUJhdCBhZGp1c3RtZW50LkZ1cnRoZXIgYXBwcm9hY2hlcyBlLmcuIHdpbnNvcml6YXRpb24gaGF2ZSBiZWVuIGFsc28gdGVzdGVkIGluIHRoaXMgc2NyaXB0LgoKIyMgTG9hZCBMaWJyYXJpZXMKYGBge3IgTG9hZF9saWJyYXJpZXMsIHdhcm5pbmc9RkFMU0UsIGVycm9yPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShEZXNjVG9vbHMpCmxpYnJhcnkocHJlcHJvY2Vzc0NvcmUpCmxpYnJhcnkoZ2dmb3J0aWZ5KQpsaWJyYXJ5KHN2YSkKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkoZ2dyZXBlbCkKYGBgCiMjIFNldCBUaGVtZQpgYGB7ciBTZXRfVGhlbWVfRm9yX1Bsb3RzfQp0aGVtZV9QdWJsaWNhdGlvbiA8LSBmdW5jdGlvbihiYXNlX3NpemU9MTQsIGJhc2VfZmFtaWx5PSJzYW5zIikgewogICAgICBsaWJyYXJ5KGdyaWQpCiAgICAgIGxpYnJhcnkoZ2d0aGVtZXMpCiAgICAgICh0aGVtZV9mb3VuZGF0aW9uKGJhc2Vfc2l6ZT1iYXNlX3NpemUsIGJhc2VfZmFtaWx5PWJhc2VfZmFtaWx5KQogICAgICAgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IHJlbCgxLjIpLCBoanVzdCA9IDAuNSwgbWFyZ2luID0gbWFyZ2luKDAsMCwyMCwwKSksCiAgICAgICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoKSwKICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSksCiAgICAgICAgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSksCiAgICAgICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSksCiAgICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIixzaXplID0gcmVsKDEpKSwKICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLHZqdXN0ID0yKSwKICAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMiksCiAgICAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgpLCAKICAgICAgICAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2xpbmUoY29sb3VyPSJibGFjayIpLAogICAgICAgICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfbGluZShjb2xvdXI9ImJsYWNrIiksCiAgICAgICAgICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXI9IiNmMGYwZjAiKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSksCiAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiLAogICAgICAgICAgICAgICBsZWdlbmQuYm94ID0gInZldGljYWwiLAogICAgICAgICAgICAgICBsZWdlbmQua2V5LnNpemU9IHVuaXQoMC41LCAiY20iKSwKICAgICAgICAgICAgICAgI2xlZ2VuZC5tYXJnaW4gPSB1bml0KDAsICJjbSIpLAogICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iaXRhbGljIiksCiAgICAgICAgICAgICAgIHBsb3QubWFyZ2luPXVuaXQoYygxMCw1LDUsNSksIm1tIiksCiAgICAgICAgICAgICAgIHN0cmlwLmJhY2tncm91bmQ9ZWxlbWVudF9yZWN0KGNvbG91cj0iI2YwZjBmMCIsZmlsbD0iI2YwZjBmMCIpLAogICAgICAgICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKQogICAgICAgKSkKICAgICAgCn0KYGBgCgojIyBEZWZpbmUgSW5wdXRzCmBgYHtyIExvYWRfaW5wdXRfZGF0YSwgbWVzc2FnZT1GQUxTRX0KbWV0aF9wZXJjX2FsbF90aWxlc192YWxpZGF0aW9uIDwtIHJlYWRSRFMoZmlsZSA9ICIvbG9jYWwvcmN1YWRyYXQvZGF0YV9mb3JfYWx0dW5hL21ldGh5bF9wZXJjX2FsbF90aWxlc19ub19DQURfdmFsaWRhdGlvbi5SRFMiKQptZXRoX3BlcmNfYWxsX3RpbGVzX1dHQlMgPC0gcmVhZFJEUyhmaWxlID0gIi9sb2NhbC9yY3VhZHJhdC9kYXRhX2Zvcl9hbHR1bmEvbWV0aHlsX3BlcmNfYWxsX3RpbGVzX25vX0NBRF9XR0JTLlJEUyIpCgptZXRhZGF0YSA8LSByZWFkUkRTKGZpbGUgPSAiL2xvY2FsL3JjdWFkcmF0L2RhdGFfZm9yX2FsdHVuYS9tZXRhZGF0YV9ub19DQUQuUkRTIikKZGF0YV9mb3Jfc2NhdHRlcnBsb3QgPC0gcmVhZFJEUyhmaWxlID0gIi9sb2NhbC9yY3VhZHJhdC9kYXRhX2Zvcl9hbHR1bmEvZGF0YV9mb3Jfc2NhdHRlcnBsb3QucmRzIikKCm1ldGh5bEJhc2VEQl92YWxpZGF0aW9uX25vX0NBRCA8LSByZWFkUkRTKCIvbG9jYWwvcmN1YWRyYXQvZGF0YV9mb3JfYWx0dW5hL21ldGh5bEJhc2VEQl92YWxpZGF0aW9uX25vX0NBRC5SRFMiKQptZXRoeWxCYXNlREJfV0dCU19hbGxfc2FtcGxlcyA8LSByZWFkUkRTKCIvbG9jYWwvcmN1YWRyYXQvZGF0YV9mb3JfYWx0dW5hL21ldGh5bEJhc2VEQl9XR0JTX2FsbF9zYW1wbGVzLlJEUyIpCgptZXRoeWxEaWZmX1dHQlMgPC0gcmVhZFJEUyhmaWxlPSAiL2xvY2FsL0FBa2FsaW5fY2FyZGlhYy9SZXN1bHRzL2NhcmRpYWMvUkRTL215RGlmZjI1cF90aWxlZF9saXN0X3YxLlJEUyIpCm1ldGh5bERpZmZfdmFsaWRhdGlvbjwtIHJlYWRSRFMoZmlsZT0gIi9sb2NhbC9yY3VhZHJhdC9kYXRhX2Zvcl9hbHR1bmEvbWV0aHlsRGlmZl92YWxpZGF0aW9uX0FDUy5SRFMiKQoKbWV0aHlsRGlmZl9XR0JTIDwtIG1ldGh5bERpZmZfV0dCU1sxOjNdCm5hbWVzKG1ldGh5bERpZmZfV0dCUyk8LWMoIlNURU1JIiwgIk5TVEVNSSIsICJVQSIpCm1ldGh5bERpZmZfV0dCUyA8LSBtZXRoeWxEaWZmX1dHQlMgJT4lIG1hcDIobmFtZXMoLiksIH4gYXNfdGliYmxlKC54KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfY29sdW1uKGNvbmRpdGlvbj0ueSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlkeXI6OnVuaXRlKHRpbGVzLCBzZXFuYW1lcywgc3RhcnQsIGVuZCwgY29uZGl0aW9uLCBzZXA9Ii4iKSkKCm1ldGh5bERpZmZfdmFsaWRhdGlvbiA8LSBtZXRoeWxEaWZmX3ZhbGlkYXRpb24gJT4lIG1hcDIobmFtZXMoLiksIH4gbWV0aHlsS2l0OjpnZXREYXRhKC54KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoLngpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkZF9jb2x1bW4oY29uZGl0aW9uPS55KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWR5cjo6dW5pdGUodGlsZXMsIGNociwgc3RhcnQsIGVuZCwgY29uZGl0aW9uLCBzZXA9Ii4iKSkKCmNsaW5pY2FsX21hcmtlcnM8LXJlYWR4bDo6cmVhZF9leGNlbCgiL2xvY2FsL0FBa2FsaW5fY2FyZGlhYy9tZXRhZGF0YS9XR0JTX1Nob3J0VGFibGVDb3JyZWxhdGlvbnMueGxzeCIpCnN1cHBsX3RibF8yIDwtIHJlYWRSRFMoIi9sb2NhbC9yY3VhZHJhdC9jZmRuYV93Z2JzL3N1cHBsX3RibF8yLlJEUyIpCmNsaW5pY2FsX21hcmtlcnM8LW1lcmdlKHN1cHBsX3RibF8yLGNsaW5pY2FsX21hcmtlcnMsYnk9IlNhbXBsZSIpCiNjbGluaWNhbF9tYXJrZXJzID0gY2xpbmljYWxfbWFya2VycyAlPiUgcmVuYW1lKCJDUlAgKG1nL2RsKSI9IkNSUChtZy9kbF88NSkiLCJUcm9wb25pblQgKG5nL2wpIj0iVHJvcG9uaW5UaHNfdDEgKG5nL2wgPDE0b3I8NTApIiwiQ0sgKFUvbCkiPSJDSyAoVS9sIF88MTkwKSIsIkNLIG1heCAoVS9sKSI9IkNLbWF4KFUvbF88MTkwKSIsIkNLLU1CIChVL2wpIj0iQ0stTUIoVS9sIDwyNCkiLCJDSy1NQiBtYXggKFUvbCkiPSJDSy1NQl9NYXgiKQpjbGluaWNhbF9tYXJrZXJzX0FDUzwtY2xpbmljYWxfbWFya2VycyAlPiUgZmlsdGVyKHRyZWF0bWVudCAhPTApCmBgYAoKIyMgQW5hbHlzaXMKIyMjIEFsbCBEYXRhCmBgYHtyIFNwZWNpZnlfc2VxdWVuY2luZ19tZXRob2RfYW5kX2Rpc2Vhc2VfaW5fbWV0YWRhdGEgfQpzZXFfbWV0aG9kIDwtIHJlcChjKCJXR0JTIiwgInRhcmdldGVkIiksIHRpbWVzID0gYygyOSwgMTEpKQptZXRhZGF0YSRzZXFfbWV0aG9kIDwtIHNlcV9tZXRob2QKCm1ldGFkYXRhIDwtIG1ldGFkYXRhICU+JQogIG11dGF0ZShjb25kaXRpb24gPSBjYXNlX3doZW4oCiAgICAodHJlYXRtZW50ID09IDApIH4gIkNvbnRyb2wiLAogICAgKHRyZWF0bWVudCA9PSAxKSB+ICJTVEVNSSIsCiAgICAodHJlYXRtZW50ID09IDIpIH4gIk5TVEVNSSIsCiAgICAodHJlYXRtZW50ID09IDMpIH4gIlVBIgogICkpCmBgYAoKYGBge3IgSW5zcGVjdF9sb2NpX29mX1dHU19hbmQgdGFyZ2V0ZWRfc2VxIGRhdGEsIGVjaG89RkFMU0V9CgojIHRpbGVfbG9jaT1saXN0KHJvd25hbWVzKG1ldGhfcGVyY19hbGxfdGlsZXNfdmFsaWRhdGlvbiksIHJvd25hbWVzKG1ldGhfcGVyY19hbGxfdGlsZXNfV0dCUykpICU+JQojICAgICAgIHNldF9uYW1lcyhjKCJ0YXJnZXQiLCJXR0JTIikpICU+JQojICAgICBtYXBfZGZyKGVuZnJhbWUsIC5pZD0ic2VxIikgJT4lCiMgICAgIHNlcGFyYXRlKHZhbHVlLCBpbnRvPWMoImNocm9tIiwic3RhcnQiLCJlbmQiKSxzZXA9IlxcLiIpCgojIHRpbGVfbG9jaSAlPiUKIyAgIGFycmFuZ2UoY2hyb20sIHN0YXJ0LCBzZXEpICU+JQojICAgaGVhZChuPTUwKQpgYGAKCmBgYHtyIE92ZXJsYXBfYW5kX0RpZmZlcmVuY2VfYmV0d2Vlbl9kYXRhX3NldF90aWxlc30KbnJvdyhtZXRoX3BlcmNfYWxsX3RpbGVzX3ZhbGlkYXRpb24pCmxlbmd0aChzZXRkaWZmKHJvd25hbWVzKG1ldGhfcGVyY19hbGxfdGlsZXNfdmFsaWRhdGlvbiksIHJvd25hbWVzKG1ldGhfcGVyY19hbGxfdGlsZXNfV0dCUykpKQpsZW5ndGgoaW50ZXJzZWN0KHJvd25hbWVzKG1ldGhfcGVyY19hbGxfdGlsZXNfdmFsaWRhdGlvbiksIHJvd25hbWVzKG1ldGhfcGVyY19hbGxfdGlsZXNfV0dCUykpKQphbGxfY29tbW9uX3RpbGVzPC1pbnRlcnNlY3Qocm93bmFtZXMobWV0aF9wZXJjX2FsbF90aWxlc192YWxpZGF0aW9uKSwgcm93bmFtZXMobWV0aF9wZXJjX2FsbF90aWxlc19XR0JTKSkKYGBgCgpGaW5kIG91dCBpZiB0aWxlcyB3aGljaCBkbyBub3QgbWF0Y2ggV0dCUyBhcmUgbWFwcGluZyB0byBzcGVjaWZpYyBsb2NhdGlvbgpBbHR1bmE6Ii4uLndlIGhhdmUgZGVzaWduZWQgcHJvYmVzIGZvciAxMEsgcmVnaW9ucyBidXQgZm9yIHdoYXRldmVyIHJlYXNvbiBzb21lIHByb2JlcyBkb27igJl0IHdvcmsgdGhhdOKAmXMgd2h5IHRhcmdldGVkIHNlcXVlbmNpbmcgZG9lc27igJl0IGNvdmVyIHdob2xlIDEwSyB0aWxlcyBidXQgc2FtZSB0aWxlcyBleGlzdCBvbiBXR0JTIGJlY2F1c2UgdGhhdCB3YXMgdGhlIGJhc2lzIG9mIG91ciBkZXNpZ24uIGxvc2luZyBwcm9iZXMgYXJlIGV4cGVjdGVkLCB0aGUgZWZmaWNpZW5jeSBvZiB0YXJnZXRpbmcgaXMgODAtOTAlIiAKYGBge3IgTWlzc2luZ190aWxlc30KbWlzc2luZ190aWxlcyA8LSBzZXRkaWZmKHJvd25hbWVzKG1ldGhfcGVyY19hbGxfdGlsZXNfdmFsaWRhdGlvbiksIHJvd25hbWVzKG1ldGhfcGVyY19hbGxfdGlsZXNfV0dCUykpCgptaXNzaW5nX3RpbGVzIDwtIHRpYmJsZShtaXNzaW5nX3RpbGVzKSAlPiUKICBzZXBhcmF0ZShtaXNzaW5nX3RpbGVzLCBpbnRvID0gYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiksIHNlcCA9ICJcXC4iKSAlPiUKICBhcnJhbmdlKGNocm9tLCBzdGFydCwgZW5kKQpgYGAKCk1hcCBjb3JyZXNwb25kaW5nIHRpbGVzIG9mIGJvdGggc2VxIG1ldGhvZHMgaW4gb25lCmBgYHtyIERldGVybWluZV90aWxlX292ZXJsYXBfYmV0d2Vlbl9zZXFfbWV0aG9kc30Kb3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlMgPC0gaW5uZXJfam9pbih4PWFzX3RpYmJsZShtZXRoX3BlcmNfYWxsX3RpbGVzX3ZhbGlkYXRpb24sIHJvd25hbWVzID0gInRpbGVzIiksIHk9YXNfdGliYmxlKG1ldGhfcGVyY19hbGxfdGlsZXNfV0dCUywgcm93bmFtZXMgPSAidGlsZXMiKSkKYGBgCgpUcmFuc2Zvcm0gdG8gbG9uZyBmb3JtYXQKYGBge3IgUmF3X0RhdGFfaW5fbG9uZ193aXRoX21ldGFkYXRhIH0KYWxsX2RhdGEgPC0gb3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlMgJT4lCiAgcGl2b3RfbG9uZ2VyKC10aWxlcywgbmFtZXNfdG8gPSAic2FtcGxlX2lkcyIsIHZhbHVlc190byA9ICJwZXJjX21ldGgiKSAlPiUKICBsZWZ0X2pvaW4obWV0YWRhdGEsIGJ5ID0gInNhbXBsZV9pZHMiKSAlPiUKICBtdXRhdGUodHJlYXRtZW50ID0gYXMuZmFjdG9yKHRyZWF0bWVudCkpCmBgYAoKIyMjIFJhdyBEYXRhCmBgYHtyIFZpb2xpbl9hbmRfQm94cGxvdHNfUmF3X0RhdGEsIGZpZy5kaW09YygxMCwxMCl9CnAxIDwtIGFsbF9kYXRhICU+JSBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBwZXJjX21ldGgsIGZpbGwgPSBzZXFfbWV0aG9kKSkgKwogIGdlb21fYm94cGxvdCgpICsKICB5bGFiKCJNZXRoeWxhdGlvbiBbJV0iKSArCiAgeGxhYigiQUNTIFR5cGUiKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIk1ldGhvZCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCnAyIDwtIGFsbF9kYXRhICU+JSBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBwZXJjX21ldGgsIGZpbGwgPSBzZXFfbWV0aG9kKSkgKwogIGdlb21fdmlvbGluKCkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKcDMgPC0gYWxsX2RhdGEgJT4lIGdncGxvdChhZXMoeCA9IGNvbmRpdGlvbiwgeSA9IHBlcmNfbWV0aCkpICsKICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHNlcV9tZXRob2QpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gc2VxX21ldGhvZCksIHdpZHRoID0gMC4wNSkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArCiAgZmFjZXRfZ3JpZChzZXFfbWV0aG9kIH4gLikKCnA0IDwtIGFsbF9kYXRhICU+JSBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBwZXJjX21ldGgpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9ICIjN0M3Q0ZGIikgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBsYWJzKHRpdGxlID0gImNvbmRpdGlvbiIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwMSwgcDIsIHAzLCBwNCwgbnJvdz0yLCBuY29sPTIsIGxhYmVscz0iQVVUTyIsIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCBsZWdlbmQ9InJpZ2h0IiksIHRleHRfZ3JvYigiUmF3IERhdGEgXG5BbGwgQ29tbW9uIFRpbGVzIiwgZmFjZSA9ICJib2xkIiwgc2l6ZT0xNikpCgpwNSA8LSBhbGxfZGF0YSAlPiUKICBmaWx0ZXIoc2VxX21ldGhvZCA9PSAiV0dCUyIpICU+JQogIGdncGxvdChhZXMoeCA9IHNhbXBsZV9pZHMsIHkgPSBwZXJjX21ldGgpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9ICIjRjg3NjZEIikgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMDUpICsKICB5bGFiKCJNZXRoeWxhdGlvbiBbJV0iKSArCiAgeGxhYigiU2FtcGxlIikgKwogIGxhYnModGl0bGUgPSAiV0dCUyIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKcDYgPC0gYWxsX2RhdGEgJT4lCiAgZmlsdGVyKHNlcV9tZXRob2QgPT0gInRhcmdldGVkIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc2FtcGxlX2lkcywgeSA9IHBlcmNfbWV0aCkpICsKICBnZW9tX3Zpb2xpbihmaWxsID0gIiMwMEJGQzQiKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wNSkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJTYW1wbGUiKSArCiAgbGFicyh0aXRsZSA9ICJUYXJnZXRlZCBTZXF1ZW5jaW5nIikgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICJNZXRob2QiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCgoKCnA3IDwtIGFsbF9kYXRhICU+JSBkcGx5cjo6Z3JvdXBfYnkoc2VxX21ldGhvZCkgJT4lIAogIGRwbHlyOjphcnJhbmdlKHNhbXBsZV9pZHMpICU+JSAKICBkcGx5cjo6bXV0YXRlKHNhbXBsZV9pZHM9ZmFjdG9yKHNhbXBsZV9pZHMpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc2FtcGxlX2lkcywgeSA9IHBlcmNfbWV0aCwgZmlsbCA9IHNlcV9tZXRob2QpKSArCiAgZ2VvbV92aW9saW4oKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wNSkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJTYW1wbGUiKSArCiAgI2xhYnModGl0bGUgPSAiUmF3IERhdGEgXG5BbGwgQ29tbW9uIFRpbGVzIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImRhcmtvcmNoaWQ0IiwgImRhcmt0dXJxdW9pc2UiKSwgbmFtZSA9ICJNZXRob2QiKSsKICB0aGVtZV9idygpKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZT0iYm9sZCIsIHNpemU9MTYpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDAuOCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSwgCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gTkEpLAogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZD1lbGVtZW50X3JlY3QoY29sb3VyPSIjZjBmMGYwIixmaWxsPSIjZjBmMGYwIiksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksCiAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2xpbmUoY29sb3VyPSJibGFjayIpLAogICAgICAgIGF4aXMubGluZS55ID0gZWxlbWVudF9saW5lKGNvbG91cj0iYmxhY2siKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gTkEpCikKCgphbm5vdGF0ZV9maWd1cmUoZ2dhcnJhbmdlKHA1LCBwNiwgbnJvdz0yLCBuY29sPTEsIGxhYmVscz0iQVVUTyIpLCB0ZXh0X2dyb2IoIlJhdyBEYXRhIFxuQWxsIENvbW1vbiBUaWxlcyIsIGZhY2UgPSAiYm9sZCIsIHNpemU9MTYpKQoKcDcKYGBgCgojIyMjIENvbXBhcmUgaG93IG1lYW4gZGlmZmVyZW5jZSBpbiBtZXRoeWxhdGlvbiBpcyBkaXN0cmlidXRlZApgYGB7ciBEaXN0cmlidXRpb25fb2ZfTWV0aHlsYXRpb25fRGlmZmVyZW5jZV9WaW9saW5wbG90LCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQpvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCUyAlPiUKICBwaXZvdF9sb25nZXIoLXRpbGVzLCBuYW1lc190byA9ICJzYW1wbGVfaWRzIiwgdmFsdWVzX3RvID0gInBlcmNfbWV0aCIpICU+JQogIGxlZnRfam9pbihtZXRhZGF0YSwgYnkgPSAic2FtcGxlX2lkcyIpICU+JQogIG11dGF0ZSh0cmVhdG1lbnQgPSBhcy5mYWN0b3IodHJlYXRtZW50KSkgJT4lCiAgZ3JvdXBfYnkodHJlYXRtZW50LCB0aWxlcywgc2VxX21ldGhvZCkgJT4lCiAgc3VtbWFyaXplKHBlcmNfbWV0aCA9IG1lYW4ocGVyY19tZXRoKSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJzZXFfbWV0aG9kIiwgdmFsdWVzX2Zyb20gPSAicGVyY19tZXRoIikgJT4lCiAgbXV0YXRlKGRpZmYgPSBXR0JTIC0gdGFyZ2V0ZWQpICU+JQogIGdncGxvdChhZXMoeCA9IHRyZWF0bWVudCwgeSA9IGRpZmYpKSArCiAgZ2VvbV92aW9saW4oKQpgYGAKCiMjIyMgQ29tcGFyZSBkaWZmZXJlbmNlIG9mIG1lYW4gb2YgYWxsIGFsbCBjb21tb24gdGlsZXMgYmV0d2VlbiB0YXJnZXRlZCBhbmQgV0dCUyBmcm9tIHJhdyBkYXRhCmBgYHtyIFNjYXR0ZXJwbG90X1Jhd19EYXRhX0NvbW1vbl9UaWxlcywgZmlnLmRpbT1jKDEwLDUpfQojIE1hcCBtZXRhZGF0YSBhbmQgcGl2b3QKb3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlNfbWVhbiA8LSBvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCUyAlPiUKICBwaXZvdF9sb25nZXIoLXRpbGVzLCBuYW1lc190byA9ICJzYW1wbGVfaWRzIiwgdmFsdWVzX3RvID0gInBlcmNfbWV0aCIpICU+JQogIGxlZnRfam9pbihtZXRhZGF0YSwgYnkgPSAic2FtcGxlX2lkcyIpICU+JQogIG11dGF0ZSh0cmVhdG1lbnQgPSBhcy5mYWN0b3IodHJlYXRtZW50KSkKCiNjYWxjdWxhdGUgbWVhbiBwZXIgY29uZGl0aW9uCm92ZXJsYXBfdGlsZXNfdmFsaWRhdGlvbl9XR0JTX21lYW4gPC0gb3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlNfbWVhbiAlPiUKICBncm91cF9ieSh0aWxlcywgc2VxX21ldGhvZCwgY29uZGl0aW9uKSAlPiUKICBzdW1tYXJpc2VfYXQodmFycyhwZXJjX21ldGgpLCBsaXN0KG5hbWUgPSBtZWFuKSkKb3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlNfbWVhbiA8LQogIGRwbHlyOjpyZW5hbWUob3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlNfbWVhbiwgbWVhbiA9ICJuYW1lIikKCiNjYWxjdWxhdGUgZGlmZmVyZW5jZSBvZiBtZWFucwpvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCU19tZWFuX2RpZmYgPC0gb3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlNfbWVhbiAlPiUKICBwaXZvdF93aWRlcih2YWx1ZXNfZnJvbSA9IG1lYW4sIG5hbWVzX2Zyb20gPWNvbmRpdGlvbikgJT4lCiAgbXV0YXRlKG1ldGguZGlmZl9TVEVNSSA9IFNURU1JIC0gQ29udHJvbCwKICAgICAgICAgbWV0aC5kaWZmX05TVEVNSSA9IE5TVEVNSSAtIENvbnRyb2wsCiAgICAgICAgIG1ldGguZGlmZl9VQSA9IFVBIC0gQ29udHJvbCkgJT4lCiAgZHBseXI6OnNlbGVjdCgtYyhDb250cm9sLCBOU1RFTUksIFNURU1JLCBVQSkpICU+JQogIGRwbHlyOjpyZW5hbWUoU1RFTUkgPSAibWV0aC5kaWZmX1NURU1JIiwgCiAgICAgICAgICAgICAgICBOU1RFTUkgPSJtZXRoLmRpZmZfTlNURU1JIiwgCiAgICAgICAgICAgICAgICBVQSA9ICJtZXRoLmRpZmZfVUEiKSAlPiUKICBwaXZvdF9sb25nZXIoLWModGlsZXMsIHNlcV9tZXRob2QpLCBuYW1lc190byA9ICJjb25kaXRpb24iLCB2YWx1ZXNfdG8gPSAibWV0aF9kaWZmIiApICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAic2VxX21ldGhvZCIsIHZhbHVlc19mcm9tID0ibWV0aF9kaWZmIikgJT4lCiAgZHBseXI6OnJlbmFtZShtZXRoLmRpZmYuV0dCUyA9ICJXR0JTIiwgbWV0aC5kaWZmLnRhcmdldGVkID0gInRhcmdldGVkIikKCgojQ2FsY3VsYXRlIHRocmVzaG9sZCBmb3Igc2NhdHRlcnBsb3QKb3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlNfbWVhbl9kaWZmIDwtIG92ZXJsYXBfdGlsZXNfdmFsaWRhdGlvbl9XR0JTX21lYW5fZGlmZiAlPiUgCiAgbXV0YXRlKHRocmVzaG9sZF8yNT0gY2FzZV93aGVuKCgoKDI1IDw9IG1ldGguZGlmZi5XR0JTKSAmICgyNSA8PSBtZXRoLmRpZmYudGFyZ2V0ZWQpKSAgfCAoKChtZXRoLmRpZmYuV0dCUyA8PS0yNSkgJiAobWV0aC5kaWZmLnRhcmdldGVkIDw9LTI1KSkpICkgfiAifDI1JXwiLCBUUlVFIH4gIm5vdCBpbiByYW5nZSIpKQoKCiMgUGxvdApvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCU19tZWFuX2RpZmYgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbWV0aC5kaWZmLnRhcmdldGVkLCB5ID0gbWV0aC5kaWZmLldHQlMsIGNvbG91cj10aHJlc2hvbGRfMjUpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDE2LCBzaXplPTIsIGFscGhhPTAuNikgKwogIHN0YXRfY29yKG1ldGhvZD0icGVhcnNvbiIpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTI1LCAyNSksIGxpbmV0eXBlPSJkb3R0ZWQiKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC0yNSwgMjUpLCBsaW5ldHlwZT0iZG90dGVkIikrCiAgeWxhYigiTWVhbiBNZXRoeWxhdGlvbiBEaWZmZXJlbmNlIFdHQlMiKSArCiAgeGxhYigiTWVhbiBNZXRoeWxhdGlvbiBEaWZmZXJlbmNlIFRhcmdldGVkIFNlcXVlbmNpbmciKSArCiAgbGFicyh0aXRsZSA9ICJSYXcgRGF0YSBcbkFsbCBDb21tb24gVGlsZXMiLCBjb2xvdXI9IlRocmVzaG9sZCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0iYm9sZCIsIHNpemU9MTYpLCBhc3BlY3QucmF0aW8gPSAxKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjOTE5NDk0IiwgIiM3Q0FFMDAiKSkrCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyhjb25kaXRpb24pKQoKcDI4IDwtCiAgb3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlNfbWVhbl9kaWZmICU+JQogIGdncGxvdChhZXMoeCA9IGNvbmRpdGlvbiwgeSA9IG1ldGguZGlmZi50YXJnZXRlZCwgZmlsbCA9IGNvbmRpdGlvbikpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgeWxhYigiTWVhbiBNZXRoeWxhdGlvbiBEaWZmZXJlbmNlIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBsYWJzKHRpdGxlID0gIlRhcmdldGVkIFNlcXVlbmNpbmciKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIkFDUyBUeXBlIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArCiAgeWxpbSgtMTAwLCAxMDApCgpwMjkgPC0KICBvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCU19tZWFuX2RpZmYgJT4lCiAgZ2dwbG90KGFlcyh4ID0gY29uZGl0aW9uLCB5ID0gbWV0aC5kaWZmLldHQlMsIGZpbGwgPSBjb25kaXRpb24pKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIHlsYWIoIk1lYW4gTWV0aHlsYXRpb24gRGlmZmVyZW5jZSBbJV0iKSArCiAgeGxhYigiQUNTIFR5cGUiKSArCiAgbGFicyh0aXRsZSA9ICJXR0JTIikgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICJBQ1MgVHlwZSIpICsKICB5bGltKC0xMDAsIDEwMCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwMjgsIHAyOSwgbnJvdz0xLCBuY29sPTIsIGxhYmVscz0iQVVUTyIsIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCBsZWdlbmQ9InJpZ2h0IiksIHRleHRfZ3JvYigiUmF3IERhdGEgXG5BbGwgQ29tbW9uIFRpbGVzIiwgZmFjZSA9ICJib2xkIiwgc2l6ZT0xNikpCmBgYAoKIyMjIFdpbnNvcml6YXRpb24KYGBge3IgV2luc29yaXphdGlvbl9Cb3hfYW5kIFZpb2xpbnBsb3RzLCBmaWcuZGltPWMoMTAsMTApfQp0aWxlcyA8LSB1bmxpc3Qob3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlNbLCAxXSkKCm92ZXJsYXBfdGlsZXNfdmFsaWRhdGlvbl9XR0JTX3dpbnNvcml6ZWQgPC0gYXNfdGliYmxlKGxhcHBseShvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCU1ssIC0xXSwgV2luc29yaXplLCBwcm9icyA9IGMoMC4xLCAwLjkpKSkgJT4lIAogIGFkZF9jb2x1bW4odGlsZXMgPSB0aWxlcywgLmJlZm9yZSA9ICIyMDE3IikgJT4lCiAgcGl2b3RfbG9uZ2VyKC10aWxlcywgbmFtZXNfdG8gPSAic2FtcGxlX2lkcyIsIHZhbHVlc190byA9ICJwZXJjX21ldGgiKSAlPiUKICBsZWZ0X2pvaW4obWV0YWRhdGEsIGJ5ID0gInNhbXBsZV9pZHMiKSAlPiUKICBtdXRhdGUodHJlYXRtZW50ID0gYXMuZmFjdG9yKHRyZWF0bWVudCkpCgojIFBsb3QgZGF0YSB0byBjb21wYXJlIG1ldGh5bGF0aW9uIGJldHdlZW4gdHJlYXRlZCBkaXNlYXNlcwpwOCA8LSBvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCU193aW5zb3JpemVkICU+JQogIGdncGxvdChhZXMoeCA9IGNvbmRpdGlvbiwgeSA9IHBlcmNfbWV0aCwgZmlsbCA9IHNlcV9tZXRob2QpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKcDkgPC0gb3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlNfd2luc29yaXplZCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBwZXJjX21ldGgsIGZpbGwgPSBzZXFfbWV0aG9kKSkgKwogIGdlb21fdmlvbGluKCkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKcDEwIDwtIG92ZXJsYXBfdGlsZXNfdmFsaWRhdGlvbl9XR0JTX3dpbnNvcml6ZWQgJT4lIGdncGxvdChhZXMoeCA9IGNvbmRpdGlvbiwgeSA9IHBlcmNfbWV0aCkpICsKICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHNlcV9tZXRob2QpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gc2VxX21ldGhvZCksIHdpZHRoID0gMC4wNSkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArCiAgZmFjZXRfZ3JpZChzZXFfbWV0aG9kIH4gLikKCnAxMSA8LSBvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCU193aW5zb3JpemVkICU+JSBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBwZXJjX21ldGgpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9ICIjN0M3Q0ZGIikgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwOCwgcDksIHAxMCwgcDExLCBjb21tb24ubGVnZW5kID0gVFJVRSwgbGVnZW5kPSJyaWdodCIsIGxhYmVscz0iQVVUTyIsIG5yb3c9MiwgbmNvbD0yKSwgdGV4dF9ncm9iKCJXaW5kc29yaXplZCBEYXRhIFxuQWxsIENvbW1vbiBUaWxlcyIsIGZhY2UgPSAiYm9sZCIsIHNpemU9MTYpKQoKcDEyIDwtIG92ZXJsYXBfdGlsZXNfdmFsaWRhdGlvbl9XR0JTX3dpbnNvcml6ZWQgJT4lCiAgZmlsdGVyKHNlcV9tZXRob2QgPT0gIldHQlMiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzYW1wbGVfaWRzLCB5ID0gcGVyY19tZXRoKSkgKwogIGdlb21fdmlvbGluKGZpbGwgPSAiI0Y4NzY2RCIpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjA1KSArCiAgeWxhYigiTWV0aHlsYXRpb24gWyVdIikgKwogIHhsYWIoIlNhbXBsZSIpICsKICBsYWJzKHRpdGxlID0gIldHQlMiKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIk1ldGhvZCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAwLjgsIGhqdXN0ID0gMSkpCgpwMTMgPC0gb3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlNfd2luc29yaXplZCAlPiUKICBmaWx0ZXIoc2VxX21ldGhvZCA9PSAidGFyZ2V0ZWQiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzYW1wbGVfaWRzLCB5ID0gcGVyY19tZXRoKSkgKwogIGdlb21fdmlvbGluKGZpbGwgPSAiIzAwQkZDNCIpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjA1KSArCiAgeWxhYigiTWV0aHlsYXRpb24gWyVdIikgKwogIHhsYWIoIlNhbXBsZSIpICsKICBsYWJzKHRpdGxlID0gIlRhcmdldGVkIikgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICJNZXRob2QiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCgpvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCU193aW5zb3JpemVkICU+JSBnZ3Bsb3QoYWVzKHggPSBzYW1wbGVfaWRzLCB5ID0gcGVyY19tZXRoLCBmaWxsID0gc2VxX21ldGhvZCkpICsKICBnZW9tX3Zpb2xpbigpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjA1KSArCiAgeWxhYigiTWV0aHlsYXRpb24gWyVdIikgKwogIHhsYWIoIlNhbXBsZSIpICsKICBsYWJzKHRpdGxlID0gIldpbmRzb3JpemVkIERhdGFcbkFsbCBDb21tb24gVGlsZXMiKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIk1ldGhvZCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiwgc2l6ZT0xNiksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC44LCBoanVzdCA9IDEpKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwMTIsIHAxMywgbnJvdz0yLCBuY29sPTEsIGxhYmVscz0iQVVUTyIpLCB0ZXh0X2dyb2IoIldpbmRzb3JpemVkIERhdGEgXG5BbGwgQ29tbW9uIFRpbGVzIiwgZmFjZSA9ICJib2xkIiwgc2l6ZT0xNikpCmBgYAoKIyMjIFF1YW50aWxlIE5vcm1hbGlzYXRpb24KYGBge3IgUXVhbnRpbGVfbm9ybWFsaXNhdGlvbiB9CiMgU2VwZXJhdGUgdGFyZ2V0ZWQgYW5kIFdHQlMgZGF0YSBpbnRvIHR3byB0aWJibGVzCnRhcmdldGVkX21ldGhfcGVyYyA8LSBvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCUyAlPiUgZHBseXI6OnNlbGVjdCgobWV0YWRhdGEgJT4lIGZpbHRlcihzZXFfbWV0aG9kID09ICJ0YXJnZXRlZCIpKSRzYW1wbGVfaWRzKQpXR0JTX21ldGhfcGVyYyA8LSBvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCUyAlPiUgZHBseXI6OnNlbGVjdCgobWV0YWRhdGEgJT4lIGZpbHRlcihzZXFfbWV0aG9kID09ICJXR0JTIikpJHNhbXBsZV9pZHMpCgojIG1ha2UgV0dCUyBkYXRhIGEgdmVjdG9yCldHQlNfbWV0aF9wZXJjX2Rpc3RyaWJ1dGlvbiA8LSBjKHQoV0dCU19tZXRoX3BlcmMpKQoKIyBub3JtYWxpc2UgYW5kIGFzc2lnbiBjb2x1bW4gbmFtZXMgdG8gZGF0YQp0YXJnZXRlZF9tZXRoX3BlcmNfbm9ybWFsaXNlZCA8LSBub3JtYWxpemUucXVhbnRpbGVzLnVzZS50YXJnZXQoYXMubWF0cml4KHRhcmdldGVkX21ldGhfcGVyYyksIFdHQlNfbWV0aF9wZXJjX2Rpc3RyaWJ1dGlvbiwgY29weSA9IFRSVUUpICU+JSBhc190aWJibGUoKQpjb2xuYW1lcyh0YXJnZXRlZF9tZXRoX3BlcmNfbm9ybWFsaXNlZCkgPC0gY29sbmFtZXModGFyZ2V0ZWRfbWV0aF9wZXJjKQoKIyBhZGQgdGlsZXMgY29sdW1uIGFuZCBqb2luIGJvdGggZGF0YWZyYW1lcwp0YXJnZXRlZF9tZXRoX3BlcmNfbm9ybWFsaXNlZCA8LSB0YXJnZXRlZF9tZXRoX3BlcmNfbm9ybWFsaXNlZCAlPiUKICBhZGRfY29sdW1uKHRpbGVzID0gdGlsZXMsIC5iZWZvcmUgPSAiMjAxNyIpCldHQlNfbWV0aF9wZXJjIDwtIFdHQlNfbWV0aF9wZXJjICU+JQogIGFkZF9jb2x1bW4odGlsZXMgPSB0aWxlcywgLmJlZm9yZSA9ICJOMSIpCgpvdmVybGFwX25vcm1hbGlzZWQgPC0gV0dCU19tZXRoX3BlcmMgJT4lIGxlZnRfam9pbih0YXJnZXRlZF9tZXRoX3BlcmNfbm9ybWFsaXNlZCwgYnkgPSAidGlsZXMiKQoKIyBtYXAgbWV0YWRhdGEgYW5kIHBpdm90Cm92ZXJsYXBfbm9ybWFsaXNlZCA8LSBvdmVybGFwX25vcm1hbGlzZWQgJT4lCiAgcGl2b3RfbG9uZ2VyKC10aWxlcywgbmFtZXNfdG8gPSAic2FtcGxlX2lkcyIsIHZhbHVlc190byA9ICJwZXJjX21ldGgiKSAlPiUKICBsZWZ0X2pvaW4obWV0YWRhdGEsIGJ5ID0gInNhbXBsZV9pZHMiKSAlPiUKICBtdXRhdGUodHJlYXRtZW50ID0gYXMuZmFjdG9yKHRyZWF0bWVudCkpCmBgYAoKYGBge3IgVmlvbGluX2FuZF9Cb3hwbG90c19RdWFudGlsZV9Ob3JtYWxpc2F0aW9uLCBmaWcuZGltPWMoMTAsMTApfQpwMTQgPC0gb3ZlcmxhcF9ub3JtYWxpc2VkICU+JSBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBwZXJjX21ldGgsIGZpbGwgPSBzZXFfbWV0aG9kKSkgKwogIGdlb21fYm94cGxvdCgpICsKICB5bGFiKCJNZXRoeWxhdGlvbiBbJV0iKSArCiAgeGxhYigiQUNTIFR5cGUiKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIk1ldGhvZCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCnAxNSA8LSBvdmVybGFwX25vcm1hbGlzZWQgJT4lIGdncGxvdChhZXMoeCA9IGNvbmRpdGlvbiwgeSA9IHBlcmNfbWV0aCwgZmlsbCA9IHNlcV9tZXRob2QpKSArCiAgZ2VvbV92aW9saW4oKSArCiAgeWxhYigiTWV0aHlsYXRpb24gWyVdIikgKwogIHhsYWIoIkFDUyBUeXBlIikgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICJNZXRob2QiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCgpwMTYgPC0gb3ZlcmxhcF9ub3JtYWxpc2VkICU+JSBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBwZXJjX21ldGgpKSArCiAgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBzZXFfbWV0aG9kKSkgKwogIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IHNlcV9tZXRob2QpLCB3aWR0aCA9IDAuMDUpICsKICB5bGFiKCJNZXRoeWxhdGlvbiBbJV0iKSArCiAgeGxhYigiQUNTIFR5cGUiKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIk1ldGhvZCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIGZhY2V0X2dyaWQoc2VxX21ldGhvZCB+IC4pCgpwMTcgPC0gb3ZlcmxhcF9ub3JtYWxpc2VkICU+JSBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBwZXJjX21ldGgpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9ICIjN0M3Q0ZGIikgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwMTQsIHAxNSwgcDE2LCBwMTcsIG5yb3c9MiwgbmNvbD0yLCBsYWJlbHM9IkFVVE8iLCBjb21tb24ubGVnZW5kID0gVFJVRSwgbGVnZW5kPSJyaWdodCIpLCB0ZXh0X2dyb2IoIlF1YW50aWxlIE5vcm1hbGlzZWQgRGF0YSBcbkFsbCBDb21tb24gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKCnAxOCA8LSBvdmVybGFwX25vcm1hbGlzZWQgJT4lCiAgZmlsdGVyKHNlcV9tZXRob2QgPT0gInRhcmdldGVkIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc2FtcGxlX2lkcywgeSA9IHBlcmNfbWV0aCkpICsKICBnZW9tX3Zpb2xpbihmaWxsID0gIiMwMEJGQzQiKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wNSkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJTYW1wbGUiKSArCiAgbGFicyh0aXRsZSA9ICJUYXJnZXRlZCBTZXF1ZW5jaW5nIikgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICJNZXRob2QiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC44LCBoanVzdCA9IDEpKQoKcDE5IDwtIG92ZXJsYXBfbm9ybWFsaXNlZCAlPiUKICBmaWx0ZXIoc2VxX21ldGhvZCA9PSAiV0dCUyIpICU+JQogIGdncGxvdChhZXMoeCA9IHNhbXBsZV9pZHMsIHkgPSBwZXJjX21ldGgpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9ICIjRjg3NjZEIikgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMDUpICsKICB5bGFiKCJNZXRoeWxhdGlvbiBbJV0iKSArCiAgeGxhYigiU2FtcGxlIikgKwogIGxhYnModGl0bGUgPSAiV0dCUyIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDAuOCwgaGp1c3QgPSAxKSkKCm92ZXJsYXBfbm9ybWFsaXNlZCAlPiUgZ2dwbG90KGFlcyh4ID0gc2FtcGxlX2lkcywgeSA9IHBlcmNfbWV0aCwgZmlsbCA9IHNlcV9tZXRob2QpKSArCiAgZ2VvbV92aW9saW4oKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wNSkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJTYW1wbGUiKSArCiAgbGFicyh0aXRsZSA9ICJRdWFudGlsZSBOb3JtYWxpc2VkIERhdGEiKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIk1ldGhvZCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiwgc2l6ZT0xNiksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC44LCBoanVzdCA9IDEpKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwMTgsIHAxOSwgbnJvdz0yLCBuY29sPTEsIGxhYmVscz0iQVVUTyIpLCB0ZXh0X2dyb2IoIlF1YW50aWxlIE5vcm1hbGlzZWQgRGF0YSBcbkFsbCBDb21tb24gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKCmBgYAoKYGBge3IgQ2FsY3VsYXRlX21lYW5fbWV0aHlsYXRpb25fb2Zfc2FtcGxlfQpvdmVybGFwX25vcm1hbGlzZWRfbWVhbiA8LSBvdmVybGFwX25vcm1hbGlzZWQgJT4lCiAgZ3JvdXBfYnkodGlsZXMsIHNlcV9tZXRob2QsIGNvbmRpdGlvbikgJT4lCiAgc3VtbWFyaXNlX2F0KHZhcnMocGVyY19tZXRoKSwgbGlzdChuYW1lID0gbWVhbikpCm92ZXJsYXBfbm9ybWFsaXNlZF9tZWFuIDwtIGRwbHlyOjpyZW5hbWUob3ZlcmxhcF9ub3JtYWxpc2VkX21lYW4sIG1lYW4gPSAibmFtZSIpCgpvdmVybGFwX25vcm1hbGlzZWRfbWVhbl9kaWZmIDwtIG92ZXJsYXBfbm9ybWFsaXNlZF9tZWFuICU+JQogIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gbWVhbiwgbmFtZXNfZnJvbSA9IGNvbmRpdGlvbikgJT4lCiAgbXV0YXRlKAogICAgbWV0aC5kaWZmX1NURU1JID0gU1RFTUkgLSBDb250cm9sLAogICAgbWV0aC5kaWZmX05TVEVNSSA9IE5TVEVNSSAtIENvbnRyb2wsCiAgICBtZXRoLmRpZmZfVUEgPSBVQSAtIENvbnRyb2wKICApICU+JQogIGRwbHlyOjpzZWxlY3QoLWMoQ29udHJvbCwgTlNURU1JLCBTVEVNSSwgVUEpKSAlPiUKICBkcGx5cjo6cmVuYW1lKFNURU1JID0gIm1ldGguZGlmZl9TVEVNSSIsIE5TVEVNSSA9ICJtZXRoLmRpZmZfTlNURU1JIiwgVUEgPSAibWV0aC5kaWZmX1VBIikgJT4lCiAgcGl2b3RfbG9uZ2VyKC1jKHRpbGVzLCBzZXFfbWV0aG9kKSwKICAgIG5hbWVzX3RvID0gImNvbmRpdGlvbiIsCiAgICB2YWx1ZXNfdG8gPSAibWV0aF9kaWZmIgogICkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJzZXFfbWV0aG9kIiwgdmFsdWVzX2Zyb20gPSAibWV0aF9kaWZmIikgJT4lCiAgZHBseXI6OnJlbmFtZShtZXRoLmRpZmYuV0dCUyA9ICJXR0JTIiwgbWV0aC5kaWZmLnRhcmdldGVkID0gInRhcmdldGVkIikKCmRhdGFfZm9yX3NjYXR0ZXJwbG90IDwtIGRhdGFfZm9yX3NjYXR0ZXJwbG90ICU+JSB0aWR5cjo6dW5pdGUodGlsZXMsIHNlcW5hbWVzLCBzdGFydCwgZW5kLCBncm91cCwgc2VwID0gIi4iKQoKb3ZlcmxhcF9ETV9kYXRhX25vcm1hbGlzZWRfbWVhbl9kaWZmIDwtIG92ZXJsYXBfbm9ybWFsaXNlZF9tZWFuX2RpZmYgJT4lCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCB0aWxlcywgY29uZGl0aW9uLCBzZXAgPSAiLiIpICU+JQogIGZpbHRlcih0aWxlcyAlaW4lIGMoZGF0YV9mb3Jfc2NhdHRlcnBsb3QkdGlsZXMpKQoKZGF0YV9mb3Jfc2NhdHRlcnBsb3QgPC0gZGF0YV9mb3Jfc2NhdHRlcnBsb3QgJT4lIHRpZHlyOjpzZXBhcmF0ZSh0aWxlcywgaW50byA9IGMoInNlcW5hbWVzIiwgInN0YXJ0IiwgImVuZCIsICJncm91cCIpLCBzZXAgPSAiXFwuIikKCm92ZXJsYXBfRE1fZGF0YV9ub3JtYWxpc2VkX21lYW5fZGlmZiA8LSBvdmVybGFwX0RNX2RhdGFfbm9ybWFsaXNlZF9tZWFuX2RpZmYgJT4lIHRpZHlyOjpzZXBhcmF0ZSh0aWxlcywgaW50byA9IGMoImNocm9tIiwgInN0YXJ0IiwgImVuZCIsICJjb25kaXRpb24iKSwgc2VwID0gIlxcLiIpCmBgYAoKQ29tcGFyZSByZWxhdGlvbnNoaXAgYmV0d2VlbiByYXcgYW5kIG5vcm1hbGlzZWQgZGF0YSBhbmQgc2VxIHRlY2huaXF1ZQpgYGB7ciBTY2F0dGVycGxvdHNfUmF3X0RhdGFfQ292ZXJhZ2Vfd2VpZ2h0ZWRfYW5kX1F1YW50aWxlX05vcm1hbGlzYXRpb24sIGZpZy5kaW09YygxMCwgMTApIH0KCiNDYWxjdWxhdGUgdGhyZXNob2xkIGZvciBzY2F0dGVycGxvdApkYXRhX2Zvcl9zY2F0dGVycGxvdCA8LSBkYXRhX2Zvcl9zY2F0dGVycGxvdCAlPiUgCiAgbXV0YXRlKHRocmVzaG9sZF8yNT0gY2FzZV93aGVuKCgoKDI1IDw9IG1ldGguZGlmZi54KSAmICgyNSA8PSBtZXRoLmRpZmYueSkpICB8ICgoKG1ldGguZGlmZi54IDw9LTI1KSAmIChtZXRoLmRpZmYueSA8PS0yNSkpKSApIH4gInwyNSV8IiwgVFJVRSB+ICJub3QgaW4gcmFuZ2UiKSkKCm92ZXJsYXBfRE1fZGF0YV9ub3JtYWxpc2VkX21lYW5fZGlmZiA8LSBvdmVybGFwX0RNX2RhdGFfbm9ybWFsaXNlZF9tZWFuX2RpZmYgJT4lIAogIG11dGF0ZSh0aHJlc2hvbGRfMjU9IGNhc2Vfd2hlbigoKCgyNSA8PSBtZXRoLmRpZmYudGFyZ2V0ZWQpICYgKDI1IDw9IG1ldGguZGlmZi5XR0JTKSkgIHwgKCgobWV0aC5kaWZmLnRhcmdldGVkIDw9LTI1KSAmIChtZXRoLmRpZmYuV0dCUyA8PS0yNSkpKSApIH4gInwyNSV8IiwgVFJVRSB+ICJub3QgaW4gcmFuZ2UiKSkKCgpwMjAgPC0gZGF0YV9mb3Jfc2NhdHRlcnBsb3QgJT4lIAogIGdncGxvdChhZXMoeCA9IG1ldGguZGlmZi54LCB5ID0gbWV0aC5kaWZmLnksIGNvbG91cj10aHJlc2hvbGRfMjUpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDE2LCBzaXplPTIsIGFscGhhPTAuNikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTI1LCAyNSksIGxpbmV0eXBlPSJkb3R0ZWQiKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC0yNSwgMjUpLCBsaW5ldHlwZT0iZG90dGVkIikrCiAgeWxhYigiV2VpZ2h0ZWQgTWVhbiBNZXRoeWxhdGlvbiBcbkRpZmZlcmVuY2UgWSIpICsKICB4bGFiKCJXZWlnaHRlZCBNZWFuIE1ldGh5bGF0aW9uIFxuRGlmZmVyZW5jZSBYIikgKwogIGxhYnModGl0bGUgPSAiUmF3IERhdGEgXG5Db3ZlcmFnZSBXZWlnaHRlZCIsIGNvbG91cj0iVGhyZXNob2xkIikgKwogIHN0YXRfY29yKG1ldGhvZD0icGVhcnNvbiIpKwogIHlsaW0oLTEwMCwgMTAwKSArCiAgeGxpbSgtMTAwLCAxMDApICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiwgc2l6ZT0xNiksIGFzcGVjdC5yYXRpbyA9IDEpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiM5MTk0OTQiLCAiIzdDQUUwMCIpKSsKICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGdyb3VwKSkKCnAyMSA8LSBvdmVybGFwX0RNX2RhdGFfbm9ybWFsaXNlZF9tZWFuX2RpZmYgJT4lIAogIGdncGxvdChhZXMoeCA9IG1ldGguZGlmZi50YXJnZXRlZCwgeSA9IG1ldGguZGlmZi5XR0JTLCBjb2xvdXI9dGhyZXNob2xkXzI1KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAxNiwgc2l6ZT0yLCBhbHBoYT0wLjYpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0yNSwgMjUpLCBsaW5ldHlwZT0iZG90dGVkIikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygtMjUsIDI1KSwgbGluZXR5cGU9ImRvdHRlZCIpKwogIHlsYWIoIk1lYW4gTWV0aHlsYXRpb24gRGlmZmVyZW5jZSBXR0JTIikgKwogIHhsYWIoIk1lYW4gTWV0aHlsYXRpb24gRGlmZmVyZW5jZSBcblRhcmdldGVkIFNlcXVlbmNpbmciKSArCiAgbGFicyh0aXRsZSA9ICJRdWFudGlsZSBOb3JtYWxpc2VkIERhdGEiLCBjb2xvdXI9IlRocmVzaG9sZCIpICsKICBzdGF0X2NvcihtZXRob2Q9InBlYXJzb24iKSsKICB5bGltKC0xMDAsIDEwMCkgKwogIHhsaW0oLTEwMCwgMTAwKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0iYm9sZCIsIHNpemU9MTYpLCBhc3BlY3QucmF0aW8gPSAxKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCAiIzkxOTQ5NCIsICIjN0NBRTAwIikpKwogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoY29uZGl0aW9uKSkKCmFubm90YXRlX2ZpZ3VyZShnZ2FycmFuZ2UocDIwLCBwMjEsIGxhYmVscz0iQVVUTyIsIG5yb3c9MiwgbmNvbD0xKSwgdGV4dF9ncm9iKCJETSBUaWxlcyIsIGZhY2UgPSAiYm9sZCIsIHNpemU9MTYpKQoKYGBgCgojIyMjIEluY2x1ZGUgd2VpZ2h0aW5nIGJ5IGNvdmVyYWdlClVzZSB3ZWlnaHRlZCBtZXRoeWxhdGlvbiBkaWZmZXJlbmNlcyBmb3IgV0dCUyBkYXRhCmBgYHtyIFNjYXR0ZXJwbG90X2NvdmVyYWdlX3dlaWdodGVkX3Jhd19kYXRhX2FuZF9jb21iaW5hdGlvbl9pbl9xdWFudGlsZV9ub3JtYWxpc2F0aW9uLCBmaWcuZGltPWMoMTAsIDEwKX0KZGF0YV9mb3Jfc2NhdHRlcnBsb3QgPC0gZGF0YV9mb3Jfc2NhdHRlcnBsb3QgJT4lIHRpZHlyOjp1bml0ZSh0aWxlcywgc2VxbmFtZXMsIHN0YXJ0LCBlbmQsIGdyb3VwLCBzZXAgPSAiLiIpCgpkaWZmX21ldGhfdGlsZXMgPC0gZGF0YV9mb3Jfc2NhdHRlcnBsb3QkdGlsZXMKCmRpZmYubWV0aC55LndlaWdodGVkIDwtIGRhdGFfZm9yX3NjYXR0ZXJwbG90ICU+JSBkcGx5cjo6c2VsZWN0KHRpbGVzLCBtZXRoLmRpZmYueSkKCm92ZXJsYXBfRE1fZGF0YV9ub3JtYWxpc2VkX21lYW5fZGlmZiA8LSBvdmVybGFwX0RNX2RhdGFfbm9ybWFsaXNlZF9tZWFuX2RpZmYgJT4lCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCBjaHJvbSwgc3RhcnQsIGVuZCwgY29uZGl0aW9uLCBzZXAgPSAiLiIpICU+JQogIGxlZnRfam9pbihkaWZmLm1ldGgueS53ZWlnaHRlZCwgYnkgPSAidGlsZXMiKSAlPiUKICB0aWR5cjo6c2VwYXJhdGUodGlsZXMsIGludG8gPSBjKCJjaHJvbSIsICJzdGFydCIsICJlbmQiLCAiY29uZGl0aW9uIiksIHNlcCA9ICJcXC4iKQoKb3ZlcmxhcF9ETV9kYXRhX25vcm1hbGlzZWRfbWVhbl9kaWZmIDwtIG92ZXJsYXBfRE1fZGF0YV9ub3JtYWxpc2VkX21lYW5fZGlmZiAlPiUgCiAgbXV0YXRlKHRocmVzaG9sZF8yNV95X3dlaWdodGVkPSBjYXNlX3doZW4oKCgoMjUgPD0gbWV0aC5kaWZmLnRhcmdldGVkKSAmICgyNSA8PSBtZXRoLmRpZmYueSkpICB8ICgoKG1ldGguZGlmZi50YXJnZXRlZCA8PS0yNSkgJiAobWV0aC5kaWZmLnkgPD0tMjUpKSkgKSB+ICJ8MjUlfCIsIFRSVUUgfiAibm90IGluIHJhbmdlIikpCgoKcDIyIDwtIG92ZXJsYXBfRE1fZGF0YV9ub3JtYWxpc2VkX21lYW5fZGlmZiAlPiUgZ2dwbG90KGFlcyh4ID0gbWV0aC5kaWZmLnRhcmdldGVkLCB5ID0gbWV0aC5kaWZmLnksIGNvbG91cj10aHJlc2hvbGRfMjVfeV93ZWlnaHRlZCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMTYsIHNpemU9MiwgYWxwaGE9MC42KSArICAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0yNSwgMjUpLCBsaW5ldHlwZT0iZG90dGVkIikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygtMjUsIDI1KSwgbGluZXR5cGU9ImRvdHRlZCIpKwogIHlsYWIoIldlaWdodGVkIE1lYW4gTWV0aHlsYXRpb24gXG5EaWZmZXJlbmNlIFdHQlMiKSArCiAgeGxhYigiTWVhbiBNZXRoeWxhdGlvbiBEaWZmZXJlbmNlIFxuVGFyZ2V0ZWQgU2VxdWVuY2luZyIpICsKICBsYWJzKHRpdGxlID0gIlF1YW50aWxlIE5vcm1hbGlzZWQgRGF0YSIsIGNvbG91cj0iVGhyZXNob2xkIikgKwogIHN0YXRfY29yKG1ldGhvZD0icGVhcnNvbiIpKwogIHlsaW0oLTEwMCwgMTAwKSArCiAgeGxpbSgtMTAwLCAxMDApICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiwgc2l6ZT0xNiksIGFzcGVjdC5yYXRpbyA9IDEpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiM5MTk0OTQiLCAiIzdDQUUwMCIpKSsKICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGNvbmRpdGlvbikpCgphbm5vdGF0ZV9maWd1cmUoZ2dhcnJhbmdlKHAyMCwgcDIyLCBsYWJlbHM9IkFVVE8iLCBucm93PTIsIG5jb2w9MSksIHRleHRfZ3JvYigiRE0gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKCmBgYAoKIyMjIyBGcm9tIHRhcmdldGVkIHNlcXVlbmNpbmcsIHdoYXQgcGVyY2VudGFnZSBsaWVzIGFib3ZlIG9yIGJlbG93ICstMjUlPwpgYGB7ciBDYWxjdWxhdGlvbl9wZXJjZW50YWdlX2Fib3ZlL2JlbG93XystMjUlX3RhcmdldGVkX3NlcX0KZGF0YV9mb3Jfc2NhdHRlcnBsb3QgPC0gZGF0YV9mb3Jfc2NhdHRlcnBsb3QgJT4lIHNlcGFyYXRlKHRpbGVzLCBpbnRvID0gYygic2VxbmFtZXMiLCAic3RhcnQiLCAiZW5kIiwgImdyb3VwIiksIHNlcCA9ICJcXC4iKQoKCnJhd192YWxpZGF0ZWQgPC0gZGF0YV9mb3Jfc2NhdHRlcnBsb3QgJT4lCiAgZ3JvdXBfYnkoZ3JvdXApICU+JQogIGRwbHlyOjpjb3VudChtZXRoLmRpZmYueCA8PS0yNSB8IG1ldGguZGlmZi54ID49MjUpICU+JSAKICBkcGx5cjo6cmVuYW1lKHRocmVzaG9sZF8yNT0yKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbT10aHJlc2hvbGRfMjUsIHZhbHVlc19mcm9tPW4pICU+JQogIGRwbHlyOjpyZW5hbWUoVmFsaWRhdGVkPTMsIE5vdF9WYWxpZGF0ZWQ9MikgJT4lCiAgbXV0YXRlKHBlcmNlbnRhZ2U9KFZhbGlkYXRlZC8oTm90X1ZhbGlkYXRlZCtWYWxpZGF0ZWQpKjEwMCkpCgpwcmludChyYXdfdmFsaWRhdGVkKQoKbm9ybV92YWxpZGF0ZWQgPC0gb3ZlcmxhcF9ETV9kYXRhX25vcm1hbGlzZWRfbWVhbl9kaWZmICU+JQogIGdyb3VwX2J5KGNvbmRpdGlvbikgJT4lCiAgZHBseXI6OmNvdW50KG1ldGguZGlmZi50YXJnZXRlZCA8PS0yNSB8IG1ldGguZGlmZi50YXJnZXRlZCA+PTI1KSAlPiUgCiAgZHBseXI6OnJlbmFtZSh0aHJlc2hvbGRfMjU9MikgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb209dGhyZXNob2xkXzI1LCB2YWx1ZXNfZnJvbT1uKSAlPiUKICBkcGx5cjo6cmVuYW1lKFZhbGlkYXRlZD0zLCBOb3RfVmFsaWRhdGVkPTIpICU+JQogIG11dGF0ZShwZXJjZW50YWdlPShWYWxpZGF0ZWQvKE5vdF9WYWxpZGF0ZWQrVmFsaWRhdGVkKSoxMDApKQoKcHJpbnQobm9ybV92YWxpZGF0ZWQpCmBgYAoKIyMjIyBEaXN0cmlidXRpb24gb2YgZGlmZmVyZW50aWFsbHkgbWV0aHlsYXRlZCB0aWxlcwpgYGB7ciBCb3hwbG90c19ETV9UaWxlc19RdWFudGlsZV9Ob3JtYWxpc2F0aW9uLCBmaWcuZGltPWMoMTAsNSl9CnAyMyA8LSBvdmVybGFwX0RNX2RhdGFfbm9ybWFsaXNlZF9tZWFuX2RpZmYgJT4lCiAgZ2dwbG90KGFlcyh4ID0gY29uZGl0aW9uLCB5ID0gbWV0aC5kaWZmLnRhcmdldGVkLCBmaWxsID0gY29uZGl0aW9uKSkgKwogIGdlb21fYm94cGxvdCgpICsKICB5bGFiKCJNZWFuIE1ldGh5bGF0aW9uIERpZmZlcmVuY2UgWyVdIikgKwogIHhsYWIoIkFDUyBUeXBlIikgKwogIGxhYnModGl0bGUgPSAiVGFyZ2V0ZWQgU2VxdWVuY2luZyIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiQUNTIFR5cGUiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0iYm9sZCIpKSArCiAgeWxpbSgtMTAwLCA4MCkKCnAyNCA8LSBvdmVybGFwX0RNX2RhdGFfbm9ybWFsaXNlZF9tZWFuX2RpZmYgJT4lCiAgZ2dwbG90KGFlcyh4ID0gY29uZGl0aW9uLCB5ID0gbWV0aC5kaWZmLldHQlMsIGZpbGwgPSBjb25kaXRpb24pKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIHlsYWIoIk1lYW4gTWV0aHlsYXRpb24gRGlmZmVyZW5jZSBbJV0iKSArCiAgeGxhYigiQUNTIFR5cGUiKSArCiAgbGFicyh0aXRsZSA9ICJXR0JTIikgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICJBQ1MgVHlwZSIpICsKICB5bGltKC0xMDAsIDgwKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0iYm9sZCIpKQoKcDI1IDwtIG92ZXJsYXBfRE1fZGF0YV9ub3JtYWxpc2VkX21lYW5fZGlmZiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBtZXRoLmRpZmYueSwgZmlsbCA9IGNvbmRpdGlvbikpICsKICBnZW9tX2JveHBsb3QoKSArCiAgeWxhYigiV2VpZ2h0ZWQgTWVhbiBNZXRoeWxhdGlvbiBEaWZmZXJlbmNlIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBsYWJzKHRpdGxlID0gIkNvdmVyYWdlIFdlaWdodGVkIFxuV0dCUyIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiQUNTIFR5cGUiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0iYm9sZCIpKSArCiAgeWxpbSgtMTAwLCA4MCkKCmFubm90YXRlX2ZpZ3VyZShnZ2FycmFuZ2UocDIzLCBwMjQsIHAyNSwgbnJvdz0xLCBuY29sPTMsIGxhYmVscz0iQVVUTyIsIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCBsZWdlbmQ9InJpZ2h0IiksIHRleHRfZ3JvYigiUXVhbnRpbGUgTm9ybWFsaXNlZCBEYXRhIFxuRE0gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKCmBgYAoKIyMjIyBEaXN0cmlidXRpb24gZnJvbSBhbGwgY29tbW9uIFRpbGVzCmBgYHtyIEJveHBsb3RzX1F1YW50aWxlX05vcm1hbGlzYXRpb24sIGZpZy5kaW09YygxMCw1KX0KcDI2IDwtIG92ZXJsYXBfbm9ybWFsaXNlZF9tZWFuX2RpZmYgJT4lIGdncGxvdChhZXMoeCA9IGNvbmRpdGlvbiwgeSA9IG1ldGguZGlmZi50YXJnZXRlZCwgZmlsbCA9IGNvbmRpdGlvbikpICsKICBnZW9tX2JveHBsb3QoKSArCiAgeWxhYigiTWVhbiBNZXRoeWxhdGlvbiBEaWZmZXJlbmNlIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBsYWJzKHRpdGxlID0gIlRhcmdldGVkIFNlcXVlbmNpbmciKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIkFDUyBUeXBlIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSkgKwogIHlsaW0oLTEwMCwgMTAwKQoKcDI3IDwtIG92ZXJsYXBfbm9ybWFsaXNlZF9tZWFuX2RpZmYgJT4lIGdncGxvdChhZXMoeCA9IGNvbmRpdGlvbiwgeSA9IG1ldGguZGlmZi5XR0JTLCBmaWxsID0gY29uZGl0aW9uKSkgKwogIGdlb21fYm94cGxvdCgpICsKICB5bGFiKCJNZWFuIE1ldGh5bGF0aW9uIERpZmZlcmVuY2UgWyVdIikgKwogIHhsYWIoIkFDUyBUeXBlIikgKwogIGxhYnModGl0bGUgPSAiV0dCUyIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiQUNTIFR5cGUiKSArCiAgeWxpbSgtMTAwLCAxMDApICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIikgKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwMjYsIHAyNywgbnJvdz0xLCBuY29sPTIsIGxhYmVscz0iQVVUTyIsIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCBsZWdlbmQ9InJpZ2h0IiksIHRleHRfZ3JvYigiUXVhbnRpbGUgTm9ybWFsaXNlZCBEYXRhIFxuQWxsIENvbW1vbiBUaWxlcyIsIGZhY2UgPSAiYm9sZCIsIHNpemU9MTYpKQoKYGBgCgojIyMjIFVzZSBQQ0EgcGVyIGNvbmRpdGlvbiBvbiBxdWFudGlsZSBub3JtYWxpc2VkIHBhdGllbnQgc2FtcGxlcyB0byBkZXBpY3QgZGlmZmVyZW5jZXMgYmV0d2VlbiB0YXJnZXRlZCBzZXEgYW5kIFdHQlMgCmBgYHtyIFBDQV9RdWFudGlsZV9Ob3JtYWxpc2F0aW9uX0FsbF9Db21tb25fVGlsZXMsIGZpZy5kaW09YygxMCwxMCl9Cm92ZXJsYXBfbm9ybWFsaXNlZF9wY2EgPC0gb3ZlcmxhcF9ub3JtYWxpc2VkICU+JSAKICBncm91cF9ieShjb25kaXRpb24pCm92ZXJsYXBfbm9ybWFsaXNlZF9wY2EgPC0gZ3JvdXBfc3BsaXQob3ZlcmxhcF9ub3JtYWxpc2VkX3BjYSkKbmFtZXMob3ZlcmxhcF9ub3JtYWxpc2VkX3BjYSkgPC0gYygiQ29udHJvbCIsICJOU1RFTUkiLCAiU1RFTUkiLCAiVUEiKQoKb3ZlcmxhcF9ub3JtYWxpc2VkX3BjYSA8LSBvdmVybGFwX25vcm1hbGlzZWRfcGNhICU+JQogIG1hcCh+IGRwbHlyOjpzZWxlY3QoLiwgdGlsZXMsIHBlcmNfbWV0aCwgc2FtcGxlX2lkcywgc2VxX21ldGhvZCkgJT4lCiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdGlsZXMsIHZhbHVlc19mcm9tID0gcGVyY19tZXRoKSklPiUKICBtYXAyKG5hbWVzKC4pLCB+IGF1dG9wbG90KHByY29tcChkcGx5cjo6c2VsZWN0KC54LCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC54LCBjb2xvdXIgPSAic2VxX21ldGhvZCIpICsKICAgIGxhYnModGl0bGUgPSAueSwgY29sb3VyPSJTZXF1ZW5jaW5nIG1ldGhvZCIpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSwgLCBhc3BlY3QucmF0aW8gPSAxKSkKCmFubm90YXRlX2ZpZ3VyZShnZ2FycmFuZ2UocGxvdGxpc3QgPSBvdmVybGFwX25vcm1hbGlzZWRfcGNhLCBucm93PTIsIG5jb2w9MiwgbGFiZWxzPSJBVVRPIiwgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIGxlZ2VuZD0icmlnaHQiKSwgdGV4dF9ncm9iKCJRdWFudGlsZSBOb3JtYWxpc2VkIERhdGEgXG5BbGwgQ29tbW9uIFRpbGVzIiwgZmFjZSA9ICJib2xkIiwgc2l6ZT0xNikpCmBgYAoKLS0+IHRoZSBzZXEgYmlhcyBpcyBzdGlsbCB2aXNpYmxlIGV2ZW4gdGhvdWdoIHF1YW50aWxlIG5vcm1hbGlzYXRpb24KCiMjIyBDb21CYXQgQWRqdXN0IHdpdGggUXVhbnRpbGUgTm9ybWFsaXNhdGlvbgojIyMjIExvZyB0cmFuc2Zvcm1hdGlvbiBvZiByYXcgZGF0YQpgYGB7ciBMb2dfdHJhbnNmb3JtYXRpb25fb2ZfcmF3X2RhdGF9CmxvZ19mdW4gPC0gZnVuY3Rpb24ob2JzZXJ2ZWQpIHsKICByZXN1bHQgPC0gKGxvZygob2JzZXJ2ZWQgKyAxKSAvICgoMTAwIC0gb2JzZXJ2ZWQpICsgMSkpKQp9CgpvdmVybGFwX2xvZyA8LSBvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCUyAlPiUKICBkcGx5cjo6c2VsZWN0X2lmKGlzLm51bWVyaWMpICU+JQogIG11dGF0ZV9hbGwobGlzdChsb2cgPSB+IGxvZ19mdW4oLikpKSAlPiUKICBpbm5lcl9qb2luKG92ZXJsYXBfdGlsZXNfdmFsaWRhdGlvbl9XR0JTKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1jKDE6NDApKSAlPiUKICByZWxvY2F0ZSgidGlsZXMiKSAlPiUKICBwaXZvdF9sb25nZXIoLXRpbGVzLCBuYW1lc190byA9ICJzYW1wbGVfaWRzIiwgdmFsdWVzX3RvID0gImxvZ190cmFuc2ZfcGVyY19tZXRoIikgJT4lCiAgbXV0YXRlKGFjcm9zcygic2FtcGxlX2lkcyIsIHN0cl9yZXBsYWNlLCAiX2xvZyIsICIiKSkgJT4lCiAgbGVmdF9qb2luKG1ldGFkYXRhICU+JSBkcGx5cjo6c2VsZWN0KHNhbXBsZV9pZHMsIGNvbmRpdGlvbiwgc2VxX21ldGhvZCksIGJ5ID0gInNhbXBsZV9pZHMiKQpgYGAKCiMjIyMgUENBIGZyb20gcmF3IGRhdGEgYWxsIGRpc2Vhc2VzIGluIGxvZyBzcGFjZSBhbGwgY29tbW9uIHRpbGVzCmBgYHtyIFBDQV9yYXdfZGF0YV9sb2dfQ29tbW9uX1RpbGVzfQoKIyBmb3IgYWxsIHRpbGVzCm92ZXJsYXBfbG9nX3BjYSA8LSBvdmVybGFwX2xvZyAlPiUKICBkcGx5cjo6c2VsZWN0KHRpbGVzLCBsb2dfdHJhbnNmX3BlcmNfbWV0aCwgc2FtcGxlX2lkcykgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRpbGVzLCB2YWx1ZXNfZnJvbSA9IGxvZ190cmFuc2ZfcGVyY19tZXRoKSAlPiUKICBsZWZ0X2pvaW4obWV0YWRhdGEgJT4lCiAgICBkcGx5cjo6c2VsZWN0KHNhbXBsZV9pZHMsIHNlcV9tZXRob2QsIGNvbmRpdGlvbiksIGJ5ID0gInNhbXBsZV9pZHMiKQoKIyBQbG90IFBDQXMgZm9yIGFsbCB0aWxlcwpwMzIgPC0gYXV0b3Bsb3QocHJjb21wKG92ZXJsYXBfbG9nX3BjYSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KHN0YXJ0c193aXRoKCJjaHIiKSkpLCBkYXRhID0gb3ZlcmxhcF9sb2dfcGNhLCBjb2xvdXIgPSAic2VxX21ldGhvZCIpICsKICBsYWJzKGNvbG91ciA9ICJNZXRob2QiKSArCiAgI2dlb21fdGV4dChzaXplID0gMiwgYWVzKGxhYmVsID0gc2FtcGxlX2lkcywgCiAgICAgICAgICAgICAgICAgICAgICAgICMgIGNvbG91ciA9IHNlcV9tZXRob2QpLCAKICAgICAgIyAgICAgIGNoZWNrX292ZXJsYXAgPSBUUlVFLCAKICAgICAgICMgICAgIG51ZGdlX3kgPSAwLjAyKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJkYXJrb3JjaGlkNCIsICJkYXJrdHVycXVvaXNlIikpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDIwKSwgCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSwgCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSksCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9IE5BKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kPWVsZW1lbnRfcmVjdChjb2xvdXI9IiNmMGYwZjAiLGZpbGw9IiNmMGYwZjAiKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwKICAgICAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfbGluZShjb2xvdXI9ImJsYWNrIiksCiAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2xpbmUoY29sb3VyPSJibGFjayIpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSkpCgpwMzMgPC0gYXV0b3Bsb3QocHJjb21wKG92ZXJsYXBfbG9nX3BjYSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IG92ZXJsYXBfbG9nX3BjYSwgY29sb3VyID0gImNvbmRpdGlvbiIpICsKICBsYWJzKGNvbG91ciA9ICJDb25kaXRpb24iKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpCgpwNTMgPC0gYXV0b3Bsb3QocHJjb21wKG92ZXJsYXBfbG9nX3BjYSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IG92ZXJsYXBfbG9nX3BjYSwgY29sb3VyID0gImNvbmRpdGlvbiIsIHNoYXBlID0gInNlcV9tZXRob2QiKSArCiAgbGFicyh0aXRsZSA9ICJSYXcgRGF0YSBMb2cgU3BhY2UgXG5BbGwgQ29tbW9uIFRpbGVzIiwgY29sb3VyID0gIkNvbmRpdGlvbiIsIHNoYXBlID0gIlNlcXVlbmNpbmcgbWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiksIGFzcGVjdC5yYXRpbyA9IDEpCgphbm5vdGF0ZV9maWd1cmUoZ2dhcnJhbmdlKHAzMiwgcDMzLCBucm93ID0gMSwgbmNvbCA9IDIsIGxhYmVscyA9ICJBVVRPIiksIHRleHRfZ3JvYigiUmF3IERhdGEgTG9nIFNwYWNlIFxuQWxsIENvbW1vbiBUaWxlcyIsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNikpCnA1MwoKCmBgYAoKIyMjIyBQQ0FzIGZyb20gcmF3IGRhdGEgc2VwZXJhdGUgZGlzZWFzZXMgaW4gbG9nIHNwYWNlIGNvbW1vbiB0aWxlcwpgYGB7ciBQQ0FfUmF3X0RhdGFfbG9nX3NwYWNlX2NvbW1vbl90aWxlcywgZmlnLmRpbT1jKDEwLDEwKX0Kb3ZlcmxhcF9ncm91cGVkX2xvZyA8LSBvdmVybGFwX2xvZyAlPiUgCiAgZ3JvdXBfYnkoY29uZGl0aW9uKSAlPiUgCiAgZ3JvdXBfc3BsaXQoKQpuYW1lcyhvdmVybGFwX2dyb3VwZWRfbG9nKSA8LSBjKCJDb250cm9sIiwgIk5TVEVNSSIsICJTVEVNSSIsICJVQSIpCgpvdmVybGFwX2dyb3VwZWRfbG9nX3BjYSA8LSBvdmVybGFwX2dyb3VwZWRfbG9nICU+JQogIGxhcHBseShGVU4gPSBmdW5jdGlvbih4KSB7CiAgICB4ICU+JQogICAgICBkcGx5cjo6c2VsZWN0KHRpbGVzLCBsb2dfdHJhbnNmX3BlcmNfbWV0aCwgc2FtcGxlX2lkcykgJT4lCiAgICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB0aWxlcywgdmFsdWVzX2Zyb20gPSBsb2dfdHJhbnNmX3BlcmNfbWV0aCkgJT4lCiAgICAgIGxlZnRfam9pbihtZXRhZGF0YSAlPiUgZHBseXI6OnNlbGVjdChzYW1wbGVfaWRzLCBzZXFfbWV0aG9kLCBjb25kaXRpb24pLCBieSA9ICJzYW1wbGVfaWRzIikKICB9KQoKIyBQbG90Cm92ZXJsYXBfZ3JvdXBlZF9sb2dfcGNhX3Bsb3QgPC0gb3ZlcmxhcF9ncm91cGVkX2xvZ19wY2EgJT4lCiAgbWFwMigKICAgIG5hbWVzKC4pLAogICAgfiBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCgueCwgc3RhcnRzX3dpdGgoImNociIpKSksIGRhdGEgPSAueCwgY29sb3VyID0gInNlcV9tZXRob2QiKSArCiAgICAgIGxhYnModGl0bGUgPSAueSwgY29sb3VyPSJTZXF1ZW5jaW5nIFxubWV0aG9kIikgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpCiAgKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwbG90bGlzdCA9b3ZlcmxhcF9ncm91cGVkX2xvZ19wY2FfcGxvdCAsIG5yb3c9MiwgbmNvbD0yLCBsYWJlbHM9IkFVVE8iLCBjb21tb24ubGVnZW5kID0gVFJVRSwgbGVnZW5kPSJyaWdodCIpLCB0ZXh0X2dyb2IoIlJhdyBEYXRhIExvZyBTcGFjZSBcbkFsbCBDb21tb24gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKYGBgCgojIyMjIFBDQXMgZnJvbSByYXcgZGF0YSBzZXBlcmF0ZSBkaXNlYXNlcyBpbiBsb2cgc3BhY2UgRE0gdGlsZXMKYGBge3IgUENBX3Jhd19kYXRhX2xvZ19zcGFjZV9ETV90aWxlcywgZmlnLmRpbT1jKDEwLDEwKX0Kb3ZlcmxhcF9ETV9sb2cgPC0gb3ZlcmxhcF9sb2cgJT4lCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCB0aWxlcywgY29uZGl0aW9uLCBzZXAgPSAiLiIpICU+JQogIGZpbHRlcih0aWxlcyAlaW4lIGMoZGlmZl9tZXRoX3RpbGVzKSkgJT4lCiAgdGlkeXI6OnNlcGFyYXRlKHRpbGVzLCBpbnRvID0gYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiwgImNvbmRpdGlvbiIpLCBzZXAgPSAiXFwuIikgJT4lCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCBjaHJvbSwgc3RhcnQsIGVuZCwgc2VwID0gIi4iKQoKb3ZlcmxhcF9ETV9ncm91cGVkX2xvZ19wY2EgPC0gb3ZlcmxhcF9ETV9sb2cgJT4lIAogIGdyb3VwX2J5KGNvbmRpdGlvbikgJT4lIAogIGdyb3VwX3NwbGl0KCkKCm5hbWVzKG92ZXJsYXBfRE1fZ3JvdXBlZF9sb2dfcGNhKSA8LSBjKCJOU1RFTUkiLCAiU1RFTUkiLCAiVUEiKQoKb3ZlcmxhcF9ETV9ncm91cGVkX2xvZ19wY2EgPC0gb3ZlcmxhcF9ETV9ncm91cGVkX2xvZ19wY2EgJT4lCiAgbGFwcGx5KEZVTiA9IGZ1bmN0aW9uKHgpIHsKICAgIHggJT4lCiAgICAgIGRwbHlyOjpzZWxlY3QodGlsZXMsIGxvZ190cmFuc2ZfcGVyY19tZXRoLCBzYW1wbGVfaWRzKSAlPiUKICAgICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRpbGVzLCB2YWx1ZXNfZnJvbSA9IGxvZ190cmFuc2ZfcGVyY19tZXRoKSAlPiUKICAgICAgbGVmdF9qb2luKG1ldGFkYXRhICU+JSBkcGx5cjo6c2VsZWN0KHNhbXBsZV9pZHMsIHNlcV9tZXRob2QsIGNvbmRpdGlvbiksIGJ5ID0gInNhbXBsZV9pZHMiKQogIH0pCgojIFBsb3QKb3ZlcmxhcF9ETV9ncm91cGVkX2xvZ19wY2FfcGxvdCA8LSBvdmVybGFwX0RNX2dyb3VwZWRfbG9nX3BjYSAlPiUKICBtYXAyKAogICAgbmFtZXMoLiksCiAgICB+IGF1dG9wbG90KHByY29tcChkcGx5cjo6c2VsZWN0KC54LCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC54LCBjb2xvdXIgPSAic2VxX21ldGhvZCIpICsKICAgICAgbGFicyh0aXRsZSA9IC55LCBjb2xvdXI9IlNlcXVlbmNpbmcgXG5tZXRob2QiKSArCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSwgYXNwZWN0LnJhdGlvID0gMSkKICApCgphbm5vdGF0ZV9maWd1cmUoZ2dhcnJhbmdlKHBsb3RsaXN0ID1vdmVybGFwX0RNX2dyb3VwZWRfbG9nX3BjYV9wbG90ICwgbnJvdz0yLCBuY29sPTIsIGxhYmVscz0iQVVUTyIsIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCBsZWdlbmQ9InJpZ2h0IiksIHRleHRfZ3JvYigiUmF3IERhdGEgTG9nIFNwYWNlIFxuRE0gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKYGBgCgojIyMjIENhbGN1bGF0ZSBxdWFudGlsZSBub3JtYWxpc2VkIGFuZCBjb21iYXRlZCBkYXRhIHBlciBjb25kaXRpb24KYGBge3IgUGVyZm9ybV9RdWFudGlsZV9Ob3JtYWxpc2F0aW9uX2FuZF9Db21iYXRfRnVuY3Rpb24sIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFfQojIFBlcmZvcm0gcXVhbnRpbGUgbm9ybWFsaXNhdGlvbiAKIyBTZXBlcmF0ZSB0YXJnZXRlZCBhbmQgV0dCUyBkYXRhIGludG8gdHdvIHRpYmJsZXMKb3ZlcmxhcF9ncm91cGVkX2xvZ190YXJnZXRlZCA8LSBvdmVybGFwX2dyb3VwZWRfbG9nICU+JSAKICBtYXAofiBkcGx5cjo6ZmlsdGVyKC4sIHNlcV9tZXRob2Q9PSd0YXJnZXRlZCcpJT4lIAogICAgICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzYW1wbGVfaWRzLCB2YWx1ZXNfZnJvbSA9IGxvZ190cmFuc2ZfcGVyY19tZXRoKSApCgpvdmVybGFwX2dyb3VwZWRfbG9nX1dHQlMgPC0gb3ZlcmxhcF9ncm91cGVkX2xvZyAlPiUgCiAgbWFwKH4gZHBseXI6OmZpbHRlciguLCBzZXFfbWV0aG9kPT0nV0dCUycpJT4lIAogICAgICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzYW1wbGVfaWRzLCB2YWx1ZXNfZnJvbSA9IGxvZ190cmFuc2ZfcGVyY19tZXRoKSApCgpvdmVybGFwX2dyb3VwZWRfbG9nX1dHQlNfZGlzdHJpYnV0aW9uIDwtIG92ZXJsYXBfZ3JvdXBlZF9sb2dfV0dCUyAlPiUgCiAgbWFwKH4gYyh0KGRwbHlyOjpzZWxlY3QoLiwgLWMoInRpbGVzIiwgImNvbmRpdGlvbiIsICJzZXFfbWV0aG9kIikpKSkpCgojbm9ybWFsaXNlIGFuZCBzZXQgY29sdW1uIGFuZCByb3duYW1lcwpvdmVybGFwX2dyb3VwZWRfbG9nX3RhcmdldGVkX25vcm1hbGlzZWQgPC0gb3ZlcmxhcF9ncm91cGVkX2xvZ190YXJnZXRlZCAlPiUgCiAgbWFwMihvdmVybGFwX2dyb3VwZWRfbG9nX1dHQlNfZGlzdHJpYnV0aW9uLCB+bm9ybWFsaXplLnF1YW50aWxlcy51c2UudGFyZ2V0KGFzLm1hdHJpeChkcGx5cjo6c2VsZWN0KC54LCAtYygidGlsZXMiLCAiY29uZGl0aW9uIiwgInNlcV9tZXRob2QiKSkpLCAueSwgY29weT1UUlVFKSAlPiUgCiAgICAgICAgIGFzX3RpYmJsZSgpICU+JSAKICAgICAgICAgc2V0X25hbWVzKGNvbG5hbWVzKGRwbHlyOjpzZWxlY3QoLngsIC1jKCJ0aWxlcyIsICJjb25kaXRpb24iLCAic2VxX21ldGhvZCIpKSkpICU+JSAKICAgICAgICAgYWRkX2NvbHVtbih0aWxlcz0ueFtbInRpbGVzIl1dLCAuYmVmb3JlPTApKQoKI0pvaW4gdGFyZ2V0ZWQgYW5kIFdHQlMgZGF0YWZyYW1lcwpvdmVybGFwX2dyb3VwZWRfbG9nX25vcm1hbGlzZWQgPC0gb3ZlcmxhcF9ncm91cGVkX2xvZ190YXJnZXRlZF9ub3JtYWxpc2VkICU+JSAKICBtYXAyKG92ZXJsYXBfZ3JvdXBlZF9sb2dfV0dCUywgfi54ICU+JSAKICAgICAgICAgZnVsbF9qb2luKC55WywtYygyOjMpXSwgYnk9InRpbGVzIikgJT4lIAogICAgICAgICBjb2x1bW5fdG9fcm93bmFtZXMoInRpbGVzIikgJT4lIAogICAgICAgICBhcy5tYXRyaXgoKSApCgoKYmF0Y2ggPC0gbWV0YWRhdGEgJT4lICAKICBtdXRhdGUoc2VxX21ldGhvZF9iaW5hcnkgPSBjYXNlX3doZW4oc2VxX21ldGhvZD09IldHQlMiIH4gMCwgc2VxX21ldGhvZD09InRhcmdldGVkIiB+IDEpKSAlPiUgCiAgZHBseXI6OnNlbGVjdChzYW1wbGVfaWRzLCBzZXFfbWV0aG9kX2JpbmFyeSkgJT4lICBkZWZyYW1lKCkKCiNSdW4gY29tYmF0IGZ1bmN0aW9uIG9uIHZhbHVlcwpvdmVybGFwX2dyb3VwZWRfbG9nX25vcm1hbGlzZWRfY29tYmF0PC0gb3ZlcmxhcF9ncm91cGVkX2xvZ19ub3JtYWxpc2VkICU+JSBtYXAofiBzdmE6OkNvbUJhdChkYXQ9LiwgYmF0Y2g9YmF0Y2hbY29sbmFtZXMoLildKSU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzX3RpYmJsZShyb3duYW1lcyA9ICJ0aWxlcyIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBpdm90X2xvbmdlcigtYyh0aWxlcyksIG5hbWVzX3RvPSJzYW1wbGVfaWRzIiwgdmFsdWVzX3RvPSJsb2dfdHJhbnNmX3BlcmNfbWV0aCIgKSAlPiUgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4obWV0YWRhdGEsIGJ5PSJzYW1wbGVfaWRzIikgJT4lICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHRyZWF0bWVudD1hcy5mYWN0b3IodHJlYXRtZW50KSkpCmBgYAoKIyMjIyBQQ0FzIG9uIGxvZyB0cmFuc2Zvcm1lZCwgcXVhbnRpbGUgbm9ybWFsaXNlZCBhbmQgY29tYmF0IGRhdGEgc2VwZXJhdGUgY29uZGl0aW9uIGNvbW1vbiB0aWxlcwpgYGB7ciBQQ0Ffb25fbG9nX3RyYW5zZm9ybWVkX3F1YW50aWxlX25vcm1hbGlzZWRfYW5kX2NvbWJhdF90cmFuc2Zvcm1lZF9kYXRhLCBmaWcuZGltPWMoMTAsMTApfQojIFBsb3QgUENBcyBwZXIgY29uZGl0aW9uCm92ZXJsYXBfZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfcGNhIDwtIG92ZXJsYXBfZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXQgJT4lCiAgbWFwMihuYW1lcyguKSwgfiBkcGx5cjo6c2VsZWN0KC54LCB0aWxlcywgbG9nX3RyYW5zZl9wZXJjX21ldGgsIHNhbXBsZV9pZHMsIHNlcV9tZXRob2QpICU+JQogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRpbGVzLCB2YWx1ZXNfZnJvbSA9IGxvZ190cmFuc2ZfcGVyY19tZXRoKSAlPiUgCiAgICBhZGRfY29sdW1uKGNvbmRpdGlvbj0ueSkgKQoKCm92ZXJsYXBfZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfcGxvdF9wZXJfZGlzZWFzZTwtIG92ZXJsYXBfZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfcGNhICU+JQogIG1hcDIobmFtZXMoLiksIH4gYXV0b3Bsb3QocHJjb21wKGRwbHlyOjpzZWxlY3QoLngsIHN0YXJ0c193aXRoKCJjaHIiKSkpLCBkYXRhID0gLngsIGNvbG91ciA9ICJzZXFfbWV0aG9kIikgKwogICAgbGFicyh0aXRsZSA9IC55LCBjb2xvdXI9IlNlcXVlbmNpbmcgXG5tZXRob2QiKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwbG90bGlzdCA9b3ZlcmxhcF9ncm91cGVkX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9wbG90X3Blcl9kaXNlYXNlICwgbnJvdz0yLCBuY29sPTIsIGxhYmVscz0iQVVUTyIsIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCBsZWdlbmQ9InJpZ2h0IiksIHRleHRfZ3JvYigiTG9nIFRyYW5zZm9ybWVkLCBRdWFudGlsZSBOb3JtYWxpc2VkIGFuZCBDb21CYXRcbkRNIFRpbGVzIiwgZmFjZSA9ICJib2xkIiwgc2l6ZT0xNikpCgpgYGAKCiMjIyMgUENBcyBvbiBsb2cgdHJhbnNmb3JtZWQsIHF1YW50aWxlIG5vcm1hbGlzZWQgYW5kIGNvbWJhdCBkYXRhIGFsbCBkaXNlYXNlcyBjb21tb24gdGlsZXMKYGBge3J9Cm92ZXJsYXBfZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfcGxvdF9hbGxfZGlzZWFzZXMgPC0gb3ZlcmxhcF9ncm91cGVkX2xvZ19ub3JtYWxpc2VkX2NvbWJhdCAlPiUKICBtYXAofiBkcGx5cjo6c2VsZWN0KC4sIHRpbGVzLCBsb2dfdHJhbnNmX3BlcmNfbWV0aCwgc2FtcGxlX2lkcywgc2VxX21ldGhvZCkgJT4lCiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdGlsZXMsIHZhbHVlc19mcm9tID0gbG9nX3RyYW5zZl9wZXJjX21ldGgpKSAlPiUKICBiaW5kX3Jvd3MoKSAlPiUKICBsZWZ0X2pvaW4obWV0YWRhdGEsIGJ5ID0gInNhbXBsZV9pZHMiKQoKcDM0IDwtIG92ZXJsYXBfZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfcGxvdF9hbGxfZGlzZWFzZXMgJT4lCiAgYXV0b3Bsb3QocHJjb21wKGRwbHlyOjpzZWxlY3QoLiwgc3RhcnRzX3dpdGgoImNociIpKSksIGRhdGEgPSAuLCBjb2xvdXIgPSAiY29uZGl0aW9uIikgKwogIGxhYnMoY29sb3VyPSJDb25kaXRpb24iKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpCgpwMzUgPC0gb3ZlcmxhcF9ncm91cGVkX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9wbG90X2FsbF9kaXNlYXNlcyAlPiUKICBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCguLCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC4sIGNvbG91ciA9ICJzZXFfbWV0aG9kLngiKSArCiAgbGFicyhjb2xvdXI9Ik1ldGhvZCIpICsKICMgZ2VvbV90ZXh0KHNpemU9MiwgYWVzKGxhYmVsPSBzYW1wbGVfaWRzLCBjb2xvdXI9c2VxX21ldGhvZC54KSwgY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIG51ZGdlX3kgPSAwLjAyKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJkYXJrb3JjaGlkNCIsICJkYXJrdHVycXVvaXNlIikpKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiLCBzaXplPTIwKSwgCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSwgCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIikrCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1jKC0wLjMsIC0wLjIsIC0wLjEsIDAsIDAuMSwgMC4yLCAwLjMpKSsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMjApLCAKICAgICAgYXNwZWN0LnJhdGlvID0gMSwgCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSksCiAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSksCiAgICAgIHN0cmlwLmJhY2tncm91bmQ9ZWxlbWVudF9yZWN0KGNvbG91cj0iI2YwZjBmMCIsZmlsbD0iI2YwZjBmMCIpLAogICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwKICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2xpbmUoY29sb3VyPSJibGFjayIpLAogICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfbGluZShjb2xvdXI9ImJsYWNrIiksCiAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSkpCgpwNTQgPC0gb3ZlcmxhcF9ncm91cGVkX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9wbG90X2FsbF9kaXNlYXNlcyAlPiUKICBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCguLCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC4sIHNoYXBlID0gInNlcV9tZXRob2QueCIsIGNvbG91cj0iY29uZGl0aW9uIikgKwogIGxhYnModGl0bGUgPSAiTG9nIFRyYW5zZm9ybWVkLCBRdWFudGlsZSBOb3JtYWxpc2VkIGFuZCBDb21CYXRcbkFsbCBDb21tb24gVGlsZXMiLCBzaGFwZT0iU2VxdWVuY2luZyBcbm1ldGhvZCIsIGNvbG91cj0iQ29uZGl0aW9uIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLCBhc3BlY3QucmF0aW8gPSAxKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwMzQsIHAzNSAsIG5yb3c9MSwgbmNvbD0yLCBsYWJlbHM9IkFVVE8iKSwgdGV4dF9ncm9iKCJMb2cgVHJhbnNmb3JtZWQsIFF1YW50aWxlIE5vcm1hbGlzZWQgYW5kIENvbUJhdFxuQWxsIENvbW1vbiBUaWxlcyIsIGZhY2UgPSAiYm9sZCIsIHNpemU9MTYpKQoKcDU0CmBgYAoKIyMjIyBQQ0FzIG9uIGxvZyB0cmFuc2Zvcm1lZCwgcXVhbnRpbGUgbm9ybWFsaXNlZCBhbmQgY29tYmF0IGRhdGEgc2VwZXJhdGUgY29uZGl0aW9uIERNIHRpbGVzCmBgYHtyIFBDQV9vbl9sb2dfdHJhbnNmb3JtZWRfcXVhbnRpbGVfbm9ybWFsaXNlZF9hbmRfY29tYmF0X2FwcGxpZWRfZGF0YV9ETV9UaWxlcywgZmlnLmRpbT1jKDEwLDEwKX0KIyBQZXJmb3JtIFBDQSBwZXIgY29uZGl0aW9uIG9uIERNIHRpbGVzCm92ZXJsYXBfRE1fZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXQgPC0gb3ZlcmxhcF9ncm91cGVkX2xvZ19ub3JtYWxpc2VkX2NvbWJhdCAlPiUgbWFwKH4gdGlkeXI6OnVuaXRlKC4sIHRpbGVzLCB0aWxlcywgY29uZGl0aW9uLCBzZXAgPSAiLiIpICU+JQogIGRwbHlyOjpmaWx0ZXIodGlsZXMgJWluJSBjKGRpZmZfbWV0aF90aWxlcykpICU+JQogIHRpZHlyOjpzZXBhcmF0ZSh0aWxlcywgaW50byA9IGMoImNocm9tIiwgInN0YXJ0IiwgImVuZCIsICJjb25kaXRpb24iKSwgc2VwID0gIlxcLiIpICU+JQogIHRpZHlyOjp1bml0ZSh0aWxlcywgY2hyb20sIHN0YXJ0LCBlbmQsIHNlcCA9ICIuIikpCgpvdmVybGFwX0RNX2dyb3VwZWRfbG9nX25vcm1hbGlzZWRfY29tYmF0IDwtIG92ZXJsYXBfRE1fZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXRbMjo0XQoKb3ZlcmxhcF9ETV9ncm91cGVkX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9wY2EgPC0gb3ZlcmxhcF9ETV9ncm91cGVkX2xvZ19ub3JtYWxpc2VkX2NvbWJhdCAlPiUKICBtYXAofiBkcGx5cjo6c2VsZWN0KC4sIHRpbGVzLCBsb2dfdHJhbnNmX3BlcmNfbWV0aCwgc2FtcGxlX2lkcywgc2VxX21ldGhvZCwgY29uZGl0aW9uKSAlPiUKICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB0aWxlcywgdmFsdWVzX2Zyb20gPSBsb2dfdHJhbnNmX3BlcmNfbWV0aCkpCgpvdmVybGFwX0RNX2dyb3VwZWRfbG9nX25vcm1hbGlzZWRfY29tYmF0X3Bsb3Rfc2VwZXJhdGVfZGlzZWFzZXMgPC0gb3ZlcmxhcF9ETV9ncm91cGVkX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9wY2EgJT4lCiAgbWFwMihuYW1lcyguKSwgfiBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCgueCwgc3RhcnRzX3dpdGgoImNociIpKSksIGRhdGEgPSAueCwgY29sb3VyID0gInNlcV9tZXRob2QiKSArCiAgICBsYWJzKHRpdGxlID0gLnksICBjb2xvdXI9IlNlcXVlbmNpbmcgXG5tZXRob2QiKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwbG90bGlzdCA9IG92ZXJsYXBfRE1fZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfcGxvdF9zZXBlcmF0ZV9kaXNlYXNlcyAsIG5yb3c9MiwgbmNvbD0yLCBsYWJlbHM9IkFVVE8iLCBjb21tb24ubGVnZW5kID0gVFJVRSwgbGVnZW5kPSJyaWdodCIpLCB0ZXh0X2dyb2IoIkxvZyBUcmFuc2Zvcm1lZCwgUXVhbnRpbGUgTm9ybWFsaXNlZCBhbmQgQ29tQmF0XG5ETSBUaWxlcyIsIGZhY2UgPSAiYm9sZCIsIHNpemU9MTYpKQoKYGBgCgojIyMjIENhbGN1bGF0ZSBsb2cgZm9sZCBjaGFuZ2UgZm9yIHF1YW50aWxlIG5vcm1hbGlzZWQgYW5kIGNvbWJhdCB0cmFuc2Zvcm1lZCBkYXRhIHNjYXR0ZXJwbG90CmBgYHtyIENhbGN1bGF0aW9uX2xvZ19mb2xkX2NoYW5nZV9mb3JfcXVhbnRpbGVfbm9ybWFsaXNlZF9hbmRfY29tYmF0X3RyYW5zZm9ybWVkX2RhdGFfc2NhdHRlcnBsb3QsIGZpZy5kaW09YygxMCw1KX0KY2FsY19sb2dfZm9sZF9jaGFuZ2UgPC0gZnVuY3Rpb24obG9nX2RhdGFmcmFtZSkgewogIGxvZ19kYXRhZnJhbWUgJT4lCiAgICBncm91cF9ieSh0aWxlcywgc2VxX21ldGhvZCwgY29uZGl0aW9uKSAlPiUKICAgIHN1bW1hcmlzZV9hdCh2YXJzKGxvZ190cmFuc2ZfcGVyY19tZXRoKSwgbGlzdChuYW1lID0gbWVhbikpICU+JQogICAgZHBseXI6OnJlbmFtZShtZWFuID0gIm5hbWUiKSAlPiUKICAgIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gbWVhbiwgbmFtZXNfZnJvbSA9IGNvbmRpdGlvbikgJT4lCiAgICBtdXRhdGUoCiAgICAgIG1ldGguZGlmZl9TVEVNSSA9IFNURU1JIC0gQ29udHJvbCwKICAgICAgbWV0aC5kaWZmX05TVEVNSSA9IE5TVEVNSSAtIENvbnRyb2wsCiAgICAgIG1ldGguZGlmZl9VQSA9IFVBIC0gQ29udHJvbAogICAgKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoLWMoQ29udHJvbCwgTlNURU1JLCBTVEVNSSwgVUEpKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoU1RFTUkgPSAibWV0aC5kaWZmX1NURU1JIiwgTlNURU1JID0gIm1ldGguZGlmZl9OU1RFTUkiLCBVQSA9ICJtZXRoLmRpZmZfVUEiKSAlPiUKICAgIHBpdm90X2xvbmdlcigtYyh0aWxlcywgc2VxX21ldGhvZCksCiAgICAgIG5hbWVzX3RvID0gImNvbmRpdGlvbiIsCiAgICAgIHZhbHVlc190byA9ICJsb2dfZm9sZF9jaGFuZ2UiCiAgICApICU+JQogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJzZXFfbWV0aG9kIiwgdmFsdWVzX2Zyb20gPSAibG9nX2ZvbGRfY2hhbmdlIikgJT4lCiAgICBkcGx5cjo6cmVuYW1lKGxvZ19mb2xkX2NoYW5nZV9XR0JTID0gIldHQlMiLCBsb2dfZm9sZF9jaGFuZ2VfdGFyZ2V0ZWQgPSAidGFyZ2V0ZWQiKQp9CgpvdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdCA8LSBvdmVybGFwX2dyb3VwZWRfbG9nX25vcm1hbGlzZWRfY29tYmF0ICU+JQogIGJpbmRfcm93cygpICU+JQogIGRwbHlyOjpzZWxlY3QoLWModHJlYXRtZW50X2Rlc2NyLCB0cmVhdG1lbnQpKQoKb3ZlcmxhcF9ncm91cGVkX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2UgPC0gb3ZlcmxhcF9ncm91cGVkX2xvZ19ub3JtYWxpc2VkX2NvbWJhdCAlPiUKICBiaW5kX3Jvd3MoKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1jKHRyZWF0bWVudF9kZXNjciwgdHJlYXRtZW50KSkgJT4lCiAgY2FsY19sb2dfZm9sZF9jaGFuZ2UoKQoKZGF0YV9mb3Jfc2NhdHRlcnBsb3QgPC0gZGF0YV9mb3Jfc2NhdHRlcnBsb3QgJT4lCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCBzZXFuYW1lcywgc3RhcnQsIGVuZCwgZ3JvdXAsIHNlcCA9ICIuIikKCm92ZXJsYXBfRE1fZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlIDwtIG92ZXJsYXBfZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlICU+JQogIHRpZHlyOjp1bml0ZSh0aWxlcywgdGlsZXMsIGNvbmRpdGlvbiwgc2VwID0gIi4iKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHRpbGVzICVpbiUgYyhkYXRhX2Zvcl9zY2F0dGVycGxvdCR0aWxlcykpICU+JQogIHRpZHlyOjpzZXBhcmF0ZSh0aWxlcywgaW50byA9IGMoImNocm9tIiwgInN0YXJ0IiwgImVuZCIsICJjb25kaXRpb24iKSwgc2VwID0gIlxcLiIpCgpkYXRhX2Zvcl9zY2F0dGVycGxvdCA8LSBkYXRhX2Zvcl9zY2F0dGVycGxvdCAlPiUKICB0aWR5cjo6c2VwYXJhdGUodGlsZXMsIGludG8gPSBjKCJzZXFuYW1lcyIsICJzdGFydCIsICJlbmQiLCAiZ3JvdXAiKSwgc2VwID0gIlxcLiIpCgojIFBsb3QKcDM5IDwtIG92ZXJsYXBfRE1fZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlICU+JSBnZ3Bsb3QoYWVzKHggPSBsb2dfZm9sZF9jaGFuZ2VfdGFyZ2V0ZWQsIHkgPSBsb2dfZm9sZF9jaGFuZ2VfV0dCUykpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjN0NBRTAwIiwgc2hhcGUgPSAxNiwgc2l6ZT0yLCBhbHBoYT0wLjYpICsKICB5bGFiKCJsb2cgZm9sZCBjaGFuZ2UgV0dCUyIpICsKICB4bGFiKCJsb2cgZm9sZCBjaGFuZ2UgVGFyZ2V0ZWQgU2VxdWVuY2luZyIpICsKICB5bGltKC01LCA1KSArCiAgbGFicyh0aXRsZSA9ICJRdWFudGlsZSBOb3JtYWxpc2F0aW9uIGFuZCBDb21CYXQiKSArCiAgc3RhdF9jb3IobWV0aG9kPSJwZWFyc29uIikrCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgIGZhY2U9ImJvbGQiKSwgYXNwZWN0LnJhdGlvID0gMSkgKwogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoY29uZGl0aW9uKSkKCmFubm90YXRlX2ZpZ3VyZShnZ2FycmFuZ2UocDM5ICwgbnJvdz0xLCBuY29sPTEpLCB0ZXh0X2dyb2IoIkRNIFRpbGVzIiwgZmFjZSA9ICJib2xkIiwgc2l6ZT0xNikpCmBgYAoKIyMjIEJhY2t0cmFuc2Zvcm1hdGlvbiBvZiBRdWFudGlsZSBOb3JtYWxpc2VkIGFuZCBDb21iYXQgRGF0YQpgYGB7ciBDYWxjdWxhdGVfbG9nX2JhY2t0cmFuc2Zvcm1hdGlvbn0KZV9mdW4gPC0gZnVuY3Rpb24ob2JzZXJ2ZWQpIHsKICByZXN1bHQgPC0gKChleHAob2JzZXJ2ZWQpICogMTAwKSAvICgxICsgZXhwKG9ic2VydmVkKSkpCn0KCm92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0IDwtIG92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0ICU+JQogIGRwbHlyOjpzZWxlY3QoLWMoInNlcV9tZXRob2QiLCAiY29uZGl0aW9uIikpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzYW1wbGVfaWRzLCB2YWx1ZXNfZnJvbSA9IGxvZ190cmFuc2ZfcGVyY19tZXRoKQoKb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nIDwtIG92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0ICU+JQogIGRwbHlyOjpzZWxlY3RfaWYoaXMubnVtZXJpYykgJT4lCiAgbXV0YXRlX2FsbChsaXN0KHBlcmNfbWV0aCA9IH4gZV9mdW4oLikpKSAlPiUKICBpbm5lcl9qb2luKG92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0KSAlPiUKICBkcGx5cjo6c2VsZWN0KC1jKDE6NDApKSAlPiUKICByZWxvY2F0ZSgidGlsZXMiKSAlPiUKICBwaXZvdF9sb25nZXIoLXRpbGVzLCBuYW1lc190byA9ICJzYW1wbGVfaWRzIiwgdmFsdWVzX3RvID0gInBlcmNfbWV0aCIpICU+JQogIG11dGF0ZShhY3Jvc3MoInNhbXBsZV9pZHMiLCBzdHJfcmVwbGFjZSwgIl9wZXJjX21ldGgiLCAiIikpICU+JQogIGxlZnRfam9pbihtZXRhZGF0YSAlPiUgZHBseXI6OnNlbGVjdChzYW1wbGVfaWRzLCBjb25kaXRpb24sIHNlcV9tZXRob2QpLCBieSA9ICJzYW1wbGVfaWRzIikKYGBgCgojIyMjIFBsb3QgJU1ldGh5bGF0aW9uIHBlciBjb25kaXRpb24gZ3JvdXAKYGBge3IgQm94X2FuZF92aW9saW5wbG90c19mb3JfYmFja3RyYW5zZm9ybWVkX25vcm1hbGlzZWRfYW5kX2NvbWJhdF90cmFuc2Zvcm1lZF9kYXRhLCBmaWcuZGltPWMoMTAsMTApfQpwNDAgPC0gb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nICU+JSBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBwZXJjX21ldGgsIGZpbGwgPSBzZXFfbWV0aG9kKSkgKwogIGdlb21fYm94cGxvdCgpICsKICB5bGFiKCJNZXRoeWxhdGlvbiBbJV0iKSArCiAgeGxhYigiQUNTIFR5cGUiKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIk1ldGhvZCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIikpCgpwNDEgPC0gb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nICU+JSBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBwZXJjX21ldGgsIGZpbGwgPSBzZXFfbWV0aG9kKSkgKwogIGdlb21fdmlvbGluKCkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSkKCnA0MiA8LSBvdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9ub19sb2cgJT4lIGdncGxvdChhZXMoeCA9IGNvbmRpdGlvbiwgeSA9IHBlcmNfbWV0aCkpICsKICBnZW9tX3Zpb2xpbihhZXMoZmlsbCA9IHNlcV9tZXRob2QpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gc2VxX21ldGhvZCksIHdpZHRoID0gMC4wNSkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSkgKwogIGZhY2V0X2dyaWQoc2VxX21ldGhvZCB+IC4pCgpwNDMgPC0gb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nICU+JSBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBwZXJjX21ldGgpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9ICIjN0M3Q0ZGIikgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJBQ1MgVHlwZSIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSkKCmFubm90YXRlX2ZpZ3VyZShnZ2FycmFuZ2UocDQwLCBwNDEsIHA0MiwgcDQzICwgbnJvdz0yLCBuY29sPTIsIGxhYmVscz0iQVVUTyIsIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCBsZWdlbmQ9InJpZ2h0IiksIHRleHRfZ3JvYigiTG9nLUJhY2t0cmFuc2Zvcm1lZCwgUXVhbnRpbGUgTm9ybWFsaXNlZCBhbmQgQ29tQmF0XG5BbGwgQ29tbW9uIFRpbGVzIiwgZmFjZSA9ICJib2xkIiwgc2l6ZT0xNikpCgpgYGAKCiMjIyMgUGxvdCAlTWV0aHlsYXRpb24gcGVyIHNhbXBsZQpgYGB7ciBQZXJfU2FtcGxlX01ldGh5bGF0aW9uX1Zpb2xpbnBsb3RzfQpwNDQgPC0gb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nICU+JQogIGZpbHRlcihzZXFfbWV0aG9kID09ICJXR0JTIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc2FtcGxlX2lkcywgeSA9IHBlcmNfbWV0aCkpICsKICBnZW9tX3Zpb2xpbihmaWxsID0gIiNGODc2NkQiKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4wNSkgKwogIHlsYWIoIk1ldGh5bGF0aW9uIFslXSIpICsKICB4bGFiKCJTYW1wbGUiKSArCiAgbGFicyh0aXRsZSA9ICJXR0JTIikgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICJNZXRob2QiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0iYm9sZCIpKQoKcDQ1IDwtIG92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0X25vX2xvZyAlPiUKICBmaWx0ZXIoc2VxX21ldGhvZCA9PSAidGFyZ2V0ZWQiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzYW1wbGVfaWRzLCB5ID0gcGVyY19tZXRoKSkgKwogIGdlb21fdmlvbGluKGZpbGwgPSAiIzAwQkZDNCIpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjA1KSArCiAgeWxhYigiTWV0aHlsYXRpb24gWyVdIikgKwogIHhsYWIoIlNhbXBsZSIpICsKICBsYWJzKHRpdGxlID0gIlRhcmdldGVkIFNlcXVlbmNpbmciKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIk1ldGhvZCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIikpCgpwNDYgPC0gb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nICU+JSBnZ3Bsb3QoYWVzKHggPSBzYW1wbGVfaWRzLCB5ID0gcGVyY19tZXRoLCBmaWxsID0gc2VxX21ldGhvZCkpICsKICBnZW9tX3Zpb2xpbigpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjA1KSArCiAgeWxhYigiTWV0aHlsYXRpb24gWyVdIikgKwogIHhsYWIoIlNhbXBsZSIpICsKICBsYWJzKHRpdGxlID0gIkxvZy1CYWNrdHJhbnNmb3JtZWQsIFF1YW50aWxlIE5vcm1hbGlzZWQgYW5kIENvbUJhdFxuQWxsIENvbW1vbiBUaWxlcyIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAwLjgsIGhqdXN0ID0gMSkpCgphbm5vdGF0ZV9maWd1cmUoZ2dhcnJhbmdlKHA0NCwgcDQ1LCBucm93PTIsIG5jb2w9MSwgbGFiZWxzPSJBVVRPIiwgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIGxlZ2VuZD0icmlnaHQiKSwgdGV4dF9ncm9iKCJMb2ctQmFja3RyYW5zZm9ybWVkLCBRdWFudGlsZSBOb3JtYWxpc2VkIGFuZCBDb21CYXRcbkFsbCBDb21tb24gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKcDQ2CmBgYAoKYGBge3IgTWFrZV9QQ0FzX0JhY2t0cmFuc2Zvcm1lZF9RdWFudGlsZV9Ob3JtYWxpc2VkX2FuZF9Db21CYXRfQWxsX0NvbW1vbl9UaWxlc30Kb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nX3Bsb3QgPC0gb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nICU+JQogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRpbGVzLCB2YWx1ZXNfZnJvbSA9IHBlcmNfbWV0aCkKCnA1NiA8LSBvdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9ub19sb2dfcGxvdCAlPiUKICBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCguLCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC4sIGNvbG91ciA9ICJjb25kaXRpb24iKSArCiAgbGFicyhjb2xvdXI9IkNvbmRpdGlvbiIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwgYXNwZWN0LnJhdGlvID0gMSkKCnA1NyA8LSBvdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9ub19sb2dfcGxvdCAlPiUKICBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCguLCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC4sIGNvbG91ciA9ICJzZXFfbWV0aG9kIikgKwogIGxhYnMoY29sb3VyPSJTZXF1ZW5jaW5nIFxubWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLCBhc3BlY3QucmF0aW8gPSAxKQoKcDU4IDwtIG92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0X25vX2xvZ19wbG90ICU+JQogIGF1dG9wbG90KHByY29tcChkcGx5cjo6c2VsZWN0KC4sIHN0YXJ0c193aXRoKCJjaHIiKSkpLCBkYXRhID0gLiwgc2hhcGUgPSAic2VxX21ldGhvZCIsIGNvbG91cj0iY29uZGl0aW9uIikgKwogIGxhYnModGl0bGUgPSAiQmFja3RyYW5zZm9ybWVkLCBRdWFudGlsZSBOb3JtYWxpc2VkIGFuZCBDb21CYXRcbkFsbCBDb21tb24gVGlsZXMiLCBzaGFwZT0iU2VxdWVuY2luZyBcbm1ldGhvZCIsIGNvbG91cj0iQ29uZGl0aW9uIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLCBhc3BlY3QucmF0aW8gPSAxKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwNTYsIHA1NyAsIG5yb3c9MSwgbmNvbD0yLCBsYWJlbHM9IkFVVE8iKSwgdGV4dF9ncm9iKCJCYWNrdHJhbnNmb3JtZWQsIFF1YW50aWxlIE5vcm1hbGlzZWQgYW5kIENvbUJhdFxuQWxsIENvbW1vbiBUaWxlcyIsIGZhY2UgPSAiYm9sZCIsIHNpemU9MTYpKQoKcDU4CmBgYAoKYGBge3IgTWFrZV9QQ0FfZm9yX0JhY2t0cmFuc2Zvcm1lZF9RdWFudGlsZV9Ob3JtYWxpc2VkX2FuZF9Db21CYXRfRE1fVGlsZXMsIGZpZy5kaW09YygxMCwxMCl9CiMgUGVyZm9ybSBQQ0EgcGVyIGNvbmRpdGlvbiBvbiBETSB0aWxlcwpvdmVybGFwX2dyb3VwZWRfbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2cgPC0gb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nICU+JSAKICBncm91cF9ieShjb25kaXRpb24pICU+JSAKICBncm91cF9zcGxpdCgpCgpvdmVybGFwX2dyb3VwZWRfRE1fbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2cgPC0gb3ZlcmxhcF9ncm91cGVkX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nICU+JSAKICBtYXAofiB0aWR5cjo6dW5pdGUoLiwgdGlsZXMsIHRpbGVzLCBjb25kaXRpb24sIHNlcCA9ICIuIikgJT4lCiAgZHBseXI6OmZpbHRlcih0aWxlcyAlaW4lIGMoZGlmZl9tZXRoX3RpbGVzKSkgJT4lCiAgdGlkeXI6OnNlcGFyYXRlKHRpbGVzLCBpbnRvID0gYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiwgImNvbmRpdGlvbiIpLCBzZXAgPSAiXFwuIikgJT4lCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCBjaHJvbSwgc3RhcnQsIGVuZCwgc2VwID0gIi4iKSkKCm92ZXJsYXBfZ3JvdXBlZF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZyA8LSBvdmVybGFwX2dyb3VwZWRfRE1fbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2dbMjo0XQoKb3ZlcmxhcF9ncm91cGVkX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3BjYSA8LSBvdmVybGFwX2dyb3VwZWRfRE1fbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2cgJT4lCiAgbWFwKH4gZHBseXI6OnNlbGVjdCguLCB0aWxlcywgcGVyY19tZXRoLCBzYW1wbGVfaWRzLCBzZXFfbWV0aG9kLCBjb25kaXRpb24pICU+JQogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRpbGVzLCB2YWx1ZXNfZnJvbSA9IHBlcmNfbWV0aCkpCgpuYW1lcyhvdmVybGFwX2dyb3VwZWRfRE1fbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2dfcGNhKSA8LSBjKCJOU1RFTUkiLCAiU1RFTUkiLCAiVUEiKQoKb3ZlcmxhcF9ncm91cGVkX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3Bsb3Rfc2VwZXJhdGVfZGlzZWFzZXMgPC0gb3ZlcmxhcF9ncm91cGVkX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3BjYSAlPiUKICBtYXAyKG5hbWVzKC4pLCB+IGF1dG9wbG90KHByY29tcChkcGx5cjo6c2VsZWN0KC54LCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC54LCBjb2xvdXIgPSAic2VxX21ldGhvZCIpICsKICAgIGxhYnModGl0bGUgPSAueSwgIGNvbG91cj0iU2VxdWVuY2luZyBcbm1ldGhvZCIpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSwgYXNwZWN0LnJhdGlvID0gMSkpCgphbm5vdGF0ZV9maWd1cmUoZ2dhcnJhbmdlKHBsb3RsaXN0ID0gb3ZlcmxhcF9ncm91cGVkX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3Bsb3Rfc2VwZXJhdGVfZGlzZWFzZXMgLCBucm93PTIsIG5jb2w9MiwgbGFiZWxzPSJBVVRPIiwgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIGxlZ2VuZD0icmlnaHQiKSwgdGV4dF9ncm9iKCJCYWNrdHJhbnNmb3JtZWQsIFF1YW50aWxlIE5vcm1hbGlzZWQgYW5kIENvbUJhdFxuRE0gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKYGBgCgpgYGB7ciBNYWtlX1BDQV9mb3JfQmFja3RyYW5zZm9ybWVkX1F1YW50aWxlX05vcm1hbGlzZWRfYW5kX0NvbUJhdF91bmlxdWVfRE1fVGlsZXMsIGZpZy5kaW09YygxMCwxMCl9CgpETV90aWxlc19OU1RFTUkgPC0gb3ZlcmxhcF9ncm91cGVkX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3BjYVtbIk5TVEVNSSJdXSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiY2hyIikpICU+JSBjb2xuYW1lcygpCkRNX3RpbGVzX1NURU1JIDwtIG92ZXJsYXBfZ3JvdXBlZF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19wY2FbWyJTVEVNSSJdXSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiY2hyIikpICU+JSBjb2xuYW1lcygpCkRNX3RpbGVzX1VBIDwtIG92ZXJsYXBfZ3JvdXBlZF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19wY2FbWyJVQSJdXSAlPiUgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiY2hyIikpICU+JSBjb2xuYW1lcygpCgpETV90aWxlc19OU1RFTUlfdW5pcXVlIDwtIHNldGRpZmYoRE1fdGlsZXNfTlNURU1JLCBETV90aWxlc19TVEVNSSkKRE1fdGlsZXNfTlNURU1JX3VuaXF1ZSA8LSBzZXRkaWZmKERNX3RpbGVzX05TVEVNSV91bmlxdWUsIERNX3RpbGVzX1VBKQoKCkRNX3RpbGVzX1NURU1JX3VuaXF1ZSA8LSBzZXRkaWZmKERNX3RpbGVzX1NURU1JLCBETV90aWxlc19OU1RFTUkpCkRNX3RpbGVzX1NURU1JX3VuaXF1ZSA8LSBzZXRkaWZmKERNX3RpbGVzX1NURU1JX3VuaXF1ZSwgRE1fdGlsZXNfVUEpCgpETV90aWxlc19VQV91bmlxdWUgPC0gc2V0ZGlmZihETV90aWxlc19VQSwgRE1fdGlsZXNfTlNURU1JKQpETV90aWxlc19VQV91bmlxdWUgPC0gc2V0ZGlmZihETV90aWxlc19VQV91bmlxdWUsIERNX3RpbGVzX1NURU1JKQoKbGVuZ3RoKERNX3RpbGVzX05TVEVNSV91bmlxdWUpICMxODcKbGVuZ3RoKERNX3RpbGVzX1NURU1JX3VuaXF1ZSkgIzQzMQpsZW5ndGgoRE1fdGlsZXNfVUFfdW5pcXVlKSAjNDczCgpvdmVybGFwX2dyb3VwZWRfdW5pcXVlX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3BjYSA8LSBsaXN0KCkKCm92ZXJsYXBfZ3JvdXBlZF91bmlxdWVfRE1fbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2dfcGNhW1siTlNURU1JIl1dIDwtIG92ZXJsYXBfZ3JvdXBlZF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19wY2FbWyJOU1RFTUkiXV0gJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlX2lkcywgc2VxX21ldGhvZCwgY29uZGl0aW9uLCBETV90aWxlc19OU1RFTUlfdW5pcXVlKQoKb3ZlcmxhcF9ncm91cGVkX3VuaXF1ZV9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19wY2FbWyJTVEVNSSJdXSA8LSBvdmVybGFwX2dyb3VwZWRfRE1fbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2dfcGNhW1siU1RFTUkiXV0gJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlX2lkcywgc2VxX21ldGhvZCwgY29uZGl0aW9uLCBETV90aWxlc19TVEVNSV91bmlxdWUpCgpvdmVybGFwX2dyb3VwZWRfdW5pcXVlX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3BjYVtbIlVBIl1dIDwtIG92ZXJsYXBfZ3JvdXBlZF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19wY2FbWyJVQSJdXSAlPiUgCiAgZHBseXI6OnNlbGVjdChzYW1wbGVfaWRzLCBzZXFfbWV0aG9kLCBjb25kaXRpb24sIERNX3RpbGVzX1VBX3VuaXF1ZSkKCgpvdmVybGFwX2dyb3VwZWRfdW5pcXVlX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3Bsb3Rfc2VwZXJhdGVfZGlzZWFzZXMgPC0gb3ZlcmxhcF9ncm91cGVkX3VuaXF1ZV9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19wY2EgJT4lCiAgbWFwMihuYW1lcyguKSwgfiBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCgueCwgc3RhcnRzX3dpdGgoImNociIpKSksIGRhdGEgPSAueCwgY29sb3VyID0gInNlcV9tZXRob2QiKSArCiAgICBsYWJzKHRpdGxlID0gLnksICBjb2xvdXI9IlNlcXVlbmNpbmcgXG5tZXRob2QiKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwbG90bGlzdCA9IG92ZXJsYXBfZ3JvdXBlZF91bmlxdWVfRE1fbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2dfcGxvdF9zZXBlcmF0ZV9kaXNlYXNlcyAsIG5yb3c9MiwgbmNvbD0yLCBsYWJlbHM9IkFVVE8iLCBjb21tb24ubGVnZW5kID0gVFJVRSwgbGVnZW5kPSJyaWdodCIpLCB0ZXh0X2dyb2IoIkJhY2t0cmFuc2Zvcm1lZCwgUXVhbnRpbGUgTm9ybWFsaXNlZCBhbmQgQ29tQmF0XG5VbmlxdWUgRE0gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKYGBgCgpgYGB7ciBNYWtlX1BDQV9mb3JfQmFja3RyYW5zZm9ybWVkX1F1YW50aWxlX05vcm1hbGlzZWRfYW5kX0NvbUJhdF9ETV9UaWxlc19yZWdhcmRsZXNfb2ZfcGVyY2VudGFnZSwgZmlnLmRpbT1jKDEwLDEwKX0KdW5pcXVlX0RNX3RpbGVzIDwtIGModW5saXN0KERNX3RpbGVzX05TVEVNSV91bmlxdWUpLCB1bmxpc3QoRE1fdGlsZXNfU1RFTUlfdW5pcXVlKSwgdW5saXN0KERNX3RpbGVzX1VBX3VuaXF1ZSkpCgojRmlsdGVyIG1ldGh5bGF0aW9uIHZhbHVlcyBmb3IgYWxsIHBlciBkaXNlYXNlIHVuaXF1ZWx5IGRpZmZlcmVudGlhbGx5IG1ldGh5bGF0ZWQgdGlsZXMKdW5pcXVlX0RNX3BlcmNfbWV0aCA8LSBvdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9ub19sb2cgJT4lIGRwbHlyOjpmaWx0ZXIodGlsZXMgJWluJSB1bmlxdWVfRE1fdGlsZXMpCgp1bmlxdWVfRE1fcGVyY19tZXRoX3BjYSA8LSB1bmlxdWVfRE1fcGVyY19tZXRoICU+JSAgCiAgdGlkeXI6OnBpdm90X3dpZGVyKHZhbHVlc19mcm9tPXBlcmNfbWV0aCwgbmFtZXNfZnJvbT10aWxlcykKCnA2MyA8LSB1bmlxdWVfRE1fcGVyY19tZXRoX3BjYSAlPiUKICBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCguLCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC4sIGNvbG91ciA9ICJjb25kaXRpb24iKSArCiAgbGFicyhjb2xvdXI9IkNvbmRpdGlvbiIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwgYXNwZWN0LnJhdGlvID0gMSkKCnA2NCA8LSB1bmlxdWVfRE1fcGVyY19tZXRoX3BjYSAlPiUKICBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCguLCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC4sIGNvbG91ciA9ICJzZXFfbWV0aG9kIikgKwogIGxhYnMoY29sb3VyPSJTZXF1ZW5jaW5nIFxubWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLCBhc3BlY3QucmF0aW8gPSAxKQoKcDY1IDwtIHVuaXF1ZV9ETV9wZXJjX21ldGhfcGNhICU+JQogIGF1dG9wbG90KHByY29tcChkcGx5cjo6c2VsZWN0KC4sIHN0YXJ0c193aXRoKCJjaHIiKSkpLCBkYXRhID0gLiwgc2hhcGUgPSAic2VxX21ldGhvZCIsIGNvbG91cj0iY29uZGl0aW9uIikgKwogIGxhYnModGl0bGUgPSAiQmFja3RyYW5zZm9ybWVkLCBRdWFudGlsZSBOb3JtYWxpc2VkIGFuZCBDb21CYXRcbkFsbCB1bmlxdWUgRE0gVGlsZXMiLCBzaGFwZT0iU2VxdWVuY2luZyBcbm1ldGhvZCIsIGNvbG91cj0iQ29uZGl0aW9uIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLCBhc3BlY3QucmF0aW8gPSAxKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwNjMsIHA2NCAsIG5yb3c9MSwgbmNvbD0yLCBsYWJlbHM9IkFVVE8iKSwgdGV4dF9ncm9iKCJCYWNrdHJhbnNmb3JtZWQsIFF1YW50aWxlIE5vcm1hbGlzZWQgYW5kIENvbUJhdFxuQWxsIHVuaXF1ZSBETSBUaWxlcyIsIGZhY2UgPSAiYm9sZCIsIHNpemU9MTYpKQoKcDY1CmBgYAoKIyMjIyBDb21wYXJlIGRpZmZlcmVuY2Ugb2YgbWVhbnMgcGVyIGNvbmRpdGlvbiBzY2F0dGVycGxvdCBhbmQgYm94cGxvdCBETQpgYGB7ciBDYWxjdWxhdGVfZGlmZmVyZW5jZV9vZl9tZWFuc19zY2F0dGVycGxvdF9hbmRfYm94cGxvdCwgZmlnLmRpbT1jKDEwLDUpfQpjYWxjX2RpZmZfb2ZfbWVhbnMgPC0gZnVuY3Rpb24oZGF0YWZyYW1lX2FsbF9zYW1wbGVzLCB0aWxlcy5jb25kaXRpb24pIHsKICBkYXRhZnJhbWVfYWxsX3NhbXBsZXNfbWVhbiA8LSBkYXRhZnJhbWVfYWxsX3NhbXBsZXMgJT4lCiAgICBncm91cF9ieSh0aWxlcywgc2VxX21ldGhvZCwgY29uZGl0aW9uKSAlPiUKICAgIHN1bW1hcmlzZV9hdCh2YXJzKHBlcmNfbWV0aCksIGxpc3QobmFtZSA9IG1lYW4pKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUobWVhbiA9ICJuYW1lIikKCiAgZGF0YWZyYW1lX2FsbF9zYW1wbGVzX21lYW5fZGlmZiA8LSBkYXRhZnJhbWVfYWxsX3NhbXBsZXNfbWVhbiAlPiUKICAgIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gbWVhbiwgbmFtZXNfZnJvbSA9IGNvbmRpdGlvbikgJT4lCiAgICBtdXRhdGUoCiAgICAgIG1ldGguZGlmZl9TVEVNSSA9IFNURU1JIC0gQ29udHJvbCwKICAgICAgbWV0aC5kaWZmX05TVEVNSSA9IE5TVEVNSSAtIENvbnRyb2wsCiAgICAgIG1ldGguZGlmZl9VQSA9IFVBIC0gQ29udHJvbAogICAgKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoLWMoQ29udHJvbCwgTlNURU1JLCBTVEVNSSwgVUEpKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoU1RFTUkgPSAibWV0aC5kaWZmX1NURU1JIiwgTlNURU1JID0gIm1ldGguZGlmZl9OU1RFTUkiLCBVQSA9ICJtZXRoLmRpZmZfVUEiKSAlPiUKICAgIHBpdm90X2xvbmdlcigtYyh0aWxlcywgc2VxX21ldGhvZCksCiAgICAgIG5hbWVzX3RvID0gImNvbmRpdGlvbiIsCiAgICAgIHZhbHVlc190byA9ICJtZXRoX2RpZmYiCiAgICApICU+JQogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJzZXFfbWV0aG9kIiwgdmFsdWVzX2Zyb20gPSAibWV0aF9kaWZmIikgJT4lCiAgICBkcGx5cjo6cmVuYW1lKG1ldGguZGlmZi5XR0JTID0gIldHQlMiLCBtZXRoLmRpZmYudGFyZ2V0ZWQgPSAidGFyZ2V0ZWQiKQoKICBkYXRhZnJhbWVfYWxsX3NhbXBsZXNfbWVhbl9kaWZmX3RpbGVzIDwtIGRhdGFmcmFtZV9hbGxfc2FtcGxlc19tZWFuX2RpZmYgJT4lCiAgICB0aWR5cjo6dW5pdGUodGlsZXMsIHRpbGVzLCBjb25kaXRpb24sIHNlcCA9ICIuIikgJT4lCiAgICBmaWx0ZXIodGlsZXMgJWluJSBjKHRpbGVzLmNvbmRpdGlvbikpICU+JQogICAgdGlkeXI6OnNlcGFyYXRlKHRpbGVzLCBpbnRvID0gYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiwgImNvbmRpdGlvbiIpLCBzZXAgPSAiXFwuIikKfQoKb3ZlcmxhcF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19tZWFuX2RpZmYgPC0gY2FsY19kaWZmX29mX21lYW5zKG92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0X25vX2xvZywgZGlmZl9tZXRoX3RpbGVzKQoKI0NhbGN1bGF0ZSB0aHJlc2hvbGQgZm9yIHNjYXR0ZXJwbG90Cm92ZXJsYXBfRE1fbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2dfbWVhbl9kaWZmIDwtIG92ZXJsYXBfRE1fbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2dfbWVhbl9kaWZmICU+JSAKICBtdXRhdGUodGhyZXNob2xkXzI1PSBjYXNlX3doZW4oKCgoMjUgPD0gbWV0aC5kaWZmLldHQlMpICYgKDI1IDw9IG1ldGguZGlmZi50YXJnZXRlZCkpICB8ICgoKG1ldGguZGlmZi5XR0JTIDw9LTI1KSAmIChtZXRoLmRpZmYudGFyZ2V0ZWQgPD0tMjUpKSkgKSB+ICJ8MjUlfCIsIFRSVUUgfiAibm90IGluIHJhbmdlIikpCgpwNDcgPC0gb3ZlcmxhcF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19tZWFuX2RpZmYgJT4lIAogIGdncGxvdChhZXMoeCA9IG1ldGguZGlmZi50YXJnZXRlZCwgeSA9IG1ldGguZGlmZi5XR0JTLCBjb2xvdXI9dGhyZXNob2xkXzI1KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAxNiwgc2l6ZT0yLCBhbHBoYT0wLjYpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTI1LCAyNSksIGxpbmV0eXBlPSJkb3R0ZWQiKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC0yNSwgMjUpLCBsaW5ldHlwZT0iZG90dGVkIikrCiAgeWxhYigiTWVhbiBNZXRoeWxhdGlvbiBEaWZmZXJlbmNlIFdHQlMiKSArCiAgeGxhYigiTWVhbiBNZXRoeWxhdGlvbiBEaWZmZXJlbmNlIFRhcmdldGVkIFNlcXVlbmNpbmciKSArCiAgbGFicyh0aXRsZSA9ICJMb2ctQmFja3RyYW5zZm9ybWVkLCBRdWFudGlsZSBOb3JtYWxpc2VkIGFuZCBDb21CYXQiLCBjb2xvdXI9IlRocmVzaG9sZCIpICsKICBzdGF0X2NvcihtZXRob2Q9InBlYXJzb24iKSsKICB5bGltKC03MCwgNzApICsKICB4bGltKC03MCwgNzApICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiM5MTk0OTQiLCAiIzdDQUUwMCIpKSsKICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGNvbmRpdGlvbikpCgphbm5vdGF0ZV9maWd1cmUoZ2dhcnJhbmdlKHA0NyAsIG5yb3c9MSwgbmNvbD0xKSwgdGV4dF9ncm9iKCJETSBUaWxlcyIsIGZhY2UgPSAiYm9sZCIsIHNpemU9MTYpKQoKIyBQbG90IGRpc3RyaWJ1dGlvbiBvZiBtZWFuIERNIHBlciBjb25kaXRpb24gYm94cGxvdHMKcDQ4IDwtIG92ZXJsYXBfRE1fbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2dfbWVhbl9kaWZmICU+JSBnZ3Bsb3QoYWVzKHggPSBjb25kaXRpb24sIHkgPSBtZXRoLmRpZmYudGFyZ2V0ZWQsIGZpbGwgPSBjb25kaXRpb24pKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIHlsYWIoIk1lYW4gTWV0aHlsYXRpb24gRGlmZmVyZW5jZSBbJV0iKSArCiAgeGxhYigiQUNTIFR5cGUiKSArCiAgbGFicyh0aXRsZSA9ICJUYXJnZXRlZCBTZXF1ZW5jaW5nIikgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICJBQ1MgVHlwZSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIHlsaW0oLTEwMCwgODApCgpwNDkgPC0gb3ZlcmxhcF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19tZWFuX2RpZmYgJT4lIGdncGxvdChhZXMoeCA9IGNvbmRpdGlvbiwgeSA9IG1ldGguZGlmZi5XR0JTLCBmaWxsID0gY29uZGl0aW9uKSkgKwogIGdlb21fYm94cGxvdCgpICsKICB5bGFiKCJNZWFuIE1ldGh5bGF0aW9uIERpZmZlcmVuY2UgWyVdIikgKwogIHhsYWIoIkFDUyBUeXBlIikgKwogIGxhYnModGl0bGUgPSAiV0dCUyIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiQUNTIFR5cGUiKSArCiAgeWxpbSgtMTAwLCA4MCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwNDgsIHA0OSAsIG5yb3c9MSwgbmNvbD0yLCBsYWJlbHM9IkFVVE8iLCBjb21tb24ubGVnZW5kID0gVFJVRSwgbGVnZW5kPSJyaWdodCIpLCB0ZXh0X2dyb2IoIkxvZy1CYWNrdHJhbnNmb3JtZWQsIFF1YW50aWxlIE5vcm1hbGlzZWQgYW5kIENvbUJhdFxuRE0gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKYGBgCmBgYHtyIEluY2x1c2lvbl9vZl9xX3ZhbHVlcywgZmlnLmRpbT1jKDEwLDUpfQojQWRkIHF2YWx1ZSB0byBkYXRhZnJhbWUgYW5kIGNhbGN1bGF0ZSBpZiB0aHJlc2hvbGQgZm9yIHF2YWx1ZSBiZWxvdyAwLjAxCmxpbT02NQoKb3ZlcmxhcF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19tZWFuX2RpZmZfcXZhbHVlcyA8LSBvdmVybGFwX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX21lYW5fZGlmZiAlPiUgCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCBjaHJvbSwgc3RhcnQsIGVuZCwgY29uZGl0aW9uLCBzZXA9Ii4iKSAlPiUgCiAgbGVmdF9qb2luKGRwbHlyOjpzZWxlY3QoYmluZF9yb3dzKG1ldGh5bERpZmZfdmFsaWRhdGlvbiksIHRpbGVzLCBxdmFsdWUpLCBieT0idGlsZXMiKSAlPiUgCiAgZHBseXI6OnJlbmFtZShxdmFsdWVfdGFyZ2V0ZWQ9IHF2YWx1ZSkgJT4lIAogIGxlZnRfam9pbihkcGx5cjo6c2VsZWN0KGJpbmRfcm93cyhtZXRoeWxEaWZmX1dHQlMpLCB0aWxlcywgcXZhbHVlKSwgYnk9InRpbGVzIikgJT4lIAogIGRwbHlyOjpyZW5hbWUocXZhbHVlX1dHQlM9cXZhbHVlKSAlPiUgCiAgdGlkeXI6OnNlcGFyYXRlKHRpbGVzLCBpbnRvPWMoImNocm9tIiwgInN0YXJ0IiwgImVuZCIsICJjb25kaXRpb24iKSkgJT4lIAogIGRwbHlyOjptdXRhdGUodGhyZXNob2xkXzI1X3F2YWx1ZT0gY2FzZV93aGVuKHRocmVzaG9sZF8yNSA9PSJ8MjUlfCIgJiBxdmFsdWVfdGFyZ2V0ZWQgPD0wLjAxICYgcXZhbHVlX1dHQlMgPD0wLjAxIH4gInNpZ25pZmljYW50IiwgVFJVRSB+ICJpbnNpZ25pZmljYW50IikpICAgICAgICAgICAgCgpwNTkgPC0gb3ZlcmxhcF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19tZWFuX2RpZmZfcXZhbHVlcyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbWV0aC5kaWZmLnRhcmdldGVkLCB5ID0gbWV0aC5kaWZmLldHQlMsIGNvbG91cj10aHJlc2hvbGRfMjVfcXZhbHVlKSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAxNiwgYWxwaGE9MC42LCBzaXplPTIpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTI1LCAyNSksIGxpbmV0eXBlPSJkb3R0ZWQiKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC0yNSwgMjUpLCBsaW5ldHlwZT0iZG90dGVkIikrCiAgeWxhYigiTWVhbiBNZXRoeWxhdGlvbiBEaWZmZXJlbmNlIFdHQlMiKSArCiAgeGxhYigiTWVhbiBNZXRoeWxhdGlvbiBEaWZmZXJlbmNlIFRhcmdldGVkIFNlcXVlbmNpbmciKSArCiAgbGFicyh0aXRsZSA9ICJMb2ctQmFja3RyYW5zZm9ybWVkLCBRdWFudGlsZSBOb3JtYWxpc2VkIGFuZCBDb21CYXQiLCBjb2xvdXI9IlRocmVzaG9sZCIpICsKICBzdGF0X2NvcihtZXRob2Q9InBlYXJzb24iKSsKICB5bGltKC1saW0sIGxpbSkgKwogIHhsaW0oLWxpbSwgbGltKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0iYm9sZCIpLCBhc3BlY3QucmF0aW8gPSAxKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjOTE5NDk0IiwgIiM3Q0FFMDAiKSkrCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyhjb25kaXRpb24pKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwNTkgLCBucm93PTEsIG5jb2w9MSksIHRleHRfZ3JvYigiRE0gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKCmBgYAojIyMjIFVuaW9uIG9mIGFsbCBETSB0aWxlcwpgYGB7ciBJbmNsdWRlX29ubHlfdW5pb25fb2ZfRE1fdGlsZXN9CiNHZXQgYWxsIHRpbGVzIG9mIGRpZmZlcmVudGlhbCBtZXRoeWxhdGlvbiByZWdhcmRsZXNzIG9mIHBlcmNlbnRhZ2UKYWxsX0RNX3RpbGVzPC0gb3ZlcmxhcF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ19tZWFuX2RpZmZfcXZhbHVlcyAlPiUgIAogICNmaWx0ZXIodGhyZXNob2xkXzI1ID09ICJ8MjUlfCIpICU+JSAKICB0aWR5cjo6dW5pdGUodGlsZXMsIGNocm9tLCBzdGFydCwgZW5kLCBzZXA9Ii4iKSAlPiUgCiAgcHVsbCh0aWxlcykgJT4lIAogIHVuaXF1ZSgpCgojRmlsdGVyIG1ldGh5bGF0aW9uIHZhbHVlcyBmb3IgYWxsIGRpZmZlcmVudGlhbGx5IG1ldGh5bGF0ZWQgdGlsZXMKYWxsX0RNX3BlcmNfbWV0aCA8LSBvdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9ub19sb2cgJT4lIGRwbHlyOjpmaWx0ZXIodGlsZXMgJWluJSBhbGxfRE1fdGlsZXMpCgphbGxfRE1fcGVyY19tZXRoX3BjYSA8LSBhbGxfRE1fcGVyY19tZXRoICU+JSAgCiAgdGlkeXI6OnBpdm90X3dpZGVyKHZhbHVlc19mcm9tPXBlcmNfbWV0aCwgbmFtZXNfZnJvbT10aWxlcykKCnA2MCA8LSBhbGxfRE1fcGVyY19tZXRoX3BjYSAlPiUKICBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCguLCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC4sIGNvbG91ciA9ICJjb25kaXRpb24iKSArCiAgbGFicyhjb2xvdXI9IkNvbmRpdGlvbiIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwgYXNwZWN0LnJhdGlvID0gMSkKCnA2MSA8LSBhbGxfRE1fcGVyY19tZXRoX3BjYSAlPiUKICBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCguLCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC4sIGNvbG91ciA9ICJzZXFfbWV0aG9kIikgKwogIGxhYnMoY29sb3VyPSJTZXF1ZW5jaW5nIFxubWV0aG9kIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLCBhc3BlY3QucmF0aW8gPSAxKQoKcDYyIDwtIGFsbF9ETV9wZXJjX21ldGhfcGNhICU+JQogIGF1dG9wbG90KHByY29tcChkcGx5cjo6c2VsZWN0KC4sIHN0YXJ0c193aXRoKCJjaHIiKSkpLCBkYXRhID0gLiwgc2hhcGUgPSAic2VxX21ldGhvZCIsIGNvbG91cj0iY29uZGl0aW9uIikgKwogIGxhYnModGl0bGUgPSAiQmFja3RyYW5zZm9ybWVkLCBRdWFudGlsZSBOb3JtYWxpc2VkIGFuZCBDb21CYXRcbkFsbCBETSBUaWxlcyIsIHNoYXBlPSJTZXF1ZW5jaW5nIFxubWV0aG9kIiwgY29sb3VyPSJDb25kaXRpb24iKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpCgphbm5vdGF0ZV9maWd1cmUoZ2dhcnJhbmdlKHA2MCwgcDYxICwgbnJvdz0xLCBuY29sPTIsIGxhYmVscz0iQVVUTyIpLCB0ZXh0X2dyb2IoIkJhY2t0cmFuc2Zvcm1lZCwgUXVhbnRpbGUgTm9ybWFsaXNlZCBhbmQgQ29tQmF0XG5BbGwgRE0gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKCnA2MgpgYGAKIyMjIyBETVJzIGJldHdlZW4gY29uZGl0aW9ucwpgYGB7ciBNYWtlX1BDQV9mcm9tX0RNUl9iZXR3ZWVuX2Rpc2Vhc2Vfc3RhdGVzfQp0b3BfRE1SX3RyZWF0bWVudCA8LSByZWFkUkRTKGZpbGUgPSAiL2xvY2FsL0FBa2FsaW5fY2FyZGlhYy9SZXN1bHRzL2NhcmRpYWMvUkRTL3RvcF9ETVJfdHJlYXRtZW50LlJEUyIpCgojRmlsdGVyIG1ldGh5bGF0aW9uIHZhbHVlcyBmb3IgYWxsIGRpZmZlcmVudGlhbGx5IG1ldGh5bGF0ZWQgdGlsZXMgYmV0d2VlbiBkaXNlYXNlCmNvbmRpdGlvbl9ETV9wZXJjX21ldGggPC0gb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nICU+JSBkcGx5cjo6ZmlsdGVyKHRpbGVzICVpbiUgdG9wX0RNUl90cmVhdG1lbnQpCgpjb25kaXRpb25fRE1fcGVyY19tZXRoX3BjYSA8LSBjb25kaXRpb25fRE1fcGVyY19tZXRoICU+JSAgCiAgdGlkeXI6OnBpdm90X3dpZGVyKHZhbHVlc19mcm9tPXBlcmNfbWV0aCwgbmFtZXNfZnJvbT10aWxlcykKCgpwNjcgPC0gY29uZGl0aW9uX0RNX3BlcmNfbWV0aF9wY2EgJT4lCiAgYXV0b3Bsb3QocHJjb21wKGRwbHlyOjpzZWxlY3QoLiwgc3RhcnRzX3dpdGgoImNociIpKSksIGRhdGEgPSAuLCBjb2xvdXIgPSAiY29uZGl0aW9uIikgKwogIGxhYnMoY29sb3VyPSJDb25kaXRpb24iKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpCgpwNjggPC0gY29uZGl0aW9uX0RNX3BlcmNfbWV0aF9wY2EgJT4lCiAgYXV0b3Bsb3QocHJjb21wKGRwbHlyOjpzZWxlY3QoLiwgc3RhcnRzX3dpdGgoImNociIpKSksIGRhdGEgPSAuLCBjb2xvdXIgPSAic2VxX21ldGhvZCIpICsKICBsYWJzKGNvbG91cj0iU2VxdWVuY2luZyBcbm1ldGhvZCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwgYXNwZWN0LnJhdGlvID0gMSkKCnA2OSA8LSBjb25kaXRpb25fRE1fcGVyY19tZXRoX3BjYSAlPiVkcGx5cjo6bXV0YXRlKGNvbmRpdGlvbiA9IGlmX2Vsc2UoY29uZGl0aW9uID09ICJDb250cm9sIiwgIkhlYWx0aHkiLCBjb25kaXRpb24pKSAlPiUKICBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCguLHN0YXJ0c193aXRoKCJjaHIiKSkpLCBkYXRhID0gLiwgc2hhcGUgPSAic2VxX21ldGhvZCIsIGNvbG91cj0iY29uZGl0aW9uIiwgc2l6ZT0zKSArCiAgI2xhYnModGl0bGUgPSAiQmFja3RyYW5zZm9ybWVkLCBRdWFudGlsZSBOb3JtYWxpc2VkIGFuZCBDb21CYXRcbkJldHdlZW4gRGlzZWFzZSBETSBUaWxlcyIsIAogIGxhYnMoc2hhcGU9IlNlcXVlbmNpbmcgXG5tZXRob2QiLCBjb2xvdXI9IkNvbmRpdGlvbiIsIGZhY2U9ImJvbGQiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjZWYzYjJjIiwiI2Y4N2YwMSIsIiMzODZjYjAiLCIjN2ZjOTdmIikpKwogIHRoZW1lX1B1YmxpY2F0aW9uKCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgCiAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIsIAogICAgICAgIGFzcGVjdC5yYXRpbyA9IDEpKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9YygtMC4zLCAtMC4yLCAtMC4xLCAwLCAwLjEsIDAuMikpKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygtMC4zLCAtMC4yLCAtMC4xLCAwLCAwLjEsIDAuMikpCgphbm5vdGF0ZV9maWd1cmUoZ2dhcnJhbmdlKHA2NywgcDY4ICwgbnJvdz0xLCBuY29sPTIsIGxhYmVscz0iQVVUTyIpLCB0ZXh0X2dyb2IoIkJhY2t0cmFuc2Zvcm1lZCwgUXVhbnRpbGUgTm9ybWFsaXNlZCBhbmQgQ29tQmF0XG5CZXR3ZWVuIERpc2Vhc2UgRE0gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKCnA2OQpgYGAKCiMjIyMgQ29tcGFyZSBWYWxpZGF0aW9uIENvaG9ydCBUaWxlcyB0byBEaXNjb3ZlcnkgQ29ob3J0IFRpbGVzCmBgYHtyIFNjYXR0ZXJwbG90X0Rpc2NvdmVyeV92c19WYWxpZGF0aW9uX0NvaG9ydH0KY29tcGFyZV9kaXNjb3ZlcnlfdmFsaWRhdGlvbiA8LSBvdmVybGFwX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX21lYW5fZGlmZl9xdmFsdWVzICU+JSAKICBkcGx5cjo6cmVuYW1lKG1ldGguZGlmZi5XR0JTLnZhbGlkYXRpb24gPSBtZXRoLmRpZmYuV0dCUywgbWV0aC5kaWZmLnRhcmdldGVkLnZhbGlkYXRpb249bWV0aC5kaWZmLnRhcmdldGVkKSAlPiUgCiAgZHBseXI6OmxlZnRfam9pbihkcGx5cjo6c2VsZWN0KGRhdGFfZm9yX3NjYXR0ZXJwbG90LCAgc2VxbmFtZXMsIHN0YXJ0LCBlbmQsIGdyb3VwLCBtZXRoLmRpZmYueSksIGJ5ID0gYygiY2hyb20iPSJzZXFuYW1lcyIsICJzdGFydCIsICJlbmQiLCAiY29uZGl0aW9uIj0iZ3JvdXAiKSkgJT4lIAogIGRwbHlyOjpyZW5hbWUobWV0aC5kaWZmLldHQlMucmF3PW1ldGguZGlmZi55KSAlPiUgCiAgZHBseXI6Om11dGF0ZSh0aHJlc2hvbGRfcXZhbHVlX2RpcmVjdGlvbmFsPSBpZmVsc2UocXZhbHVlX3RhcmdldGVkIDwgMC4wMSAmIHF2YWx1ZV9XR0JTIDwgMC4wMSAmIChtZXRoLmRpZmYudGFyZ2V0ZWQudmFsaWRhdGlvbiA+PSAwICYgbWV0aC5kaWZmLldHQlMucmF3ID49IDAgfCBtZXRoLmRpZmYudGFyZ2V0ZWQudmFsaWRhdGlvbiA8PSAwICYgbWV0aC5kaWZmLldHQlMucmF3IDw9IDApLCAic2lnbmlmaWNhbnQiLCAiaW5zaWduaWZpY2FudCIpLAogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB0aHJlc2hvbGRfcXZhbHVlPSBpZmVsc2UocXZhbHVlX3RhcmdldGVkIDwgMC4wMSAmIHF2YWx1ZV9XR0JTIDwgMC4wMSwgICJzaWduaWZpY2FudCIsICJpbnNpZ25pZmljYW50IiksCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIHRocmVzaG9sZF8yNV9jb2hvcnRfY29tcGFyaXNvbiA9IGlmZWxzZSgobWV0aC5kaWZmLldHQlMucmF3ID49IDI1ICYgbWV0aC5kaWZmLnRhcmdldGVkLnZhbGlkYXRpb24gPj0gMjUgfCBtZXRoLmRpZmYuV0dCUy5yYXcgPD0gLTI1ICYgbWV0aC5kaWZmLnRhcmdldGVkLnZhbGlkYXRpb24gPD0gLTI1KSwgIkRNUiB2YWxpZGF0ZWQiLCAiRE1SIG5vdCB2YWxpZGF0ZWQiKSwKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdGhyZXNob2xkXzI1X3F2YWx1ZV9jb2hvcnRfY29tcGFyaXNvbiA9IGNhc2Vfd2hlbih0aHJlc2hvbGRfMjVfY29ob3J0X2NvbXBhcmlzb24gPT0gIkRNUiB2YWxpZGF0ZWQiICYgdGhyZXNob2xkX3F2YWx1ZV9kaXJlY3Rpb25hbCA9PSAic2lnbmlmaWNhbnQiIH4gInNpZ25pZmljYW50IGFuZCB2YWxpZGF0ZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyZXNob2xkXzI1X2NvaG9ydF9jb21wYXJpc29uID09ICJETVIgdmFsaWRhdGVkIiAmIHRocmVzaG9sZF9xdmFsdWVfZGlyZWN0aW9uYWwgPT0gImluc2lnbmlmaWNhbnQiIH4gImluc2lnbmlmaWNhbnQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyZXNob2xkXzI1X2NvaG9ydF9jb21wYXJpc29uID09ICJETVIgbm90IHZhbGlkYXRlZCIgJiB0aHJlc2hvbGRfcXZhbHVlX2RpcmVjdGlvbmFsID09ICJzaWduaWZpY2FudCIgfiAic2lnbmlmaWNhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJlc2hvbGRfMjVfY29ob3J0X2NvbXBhcmlzb24gPT0gIkRNUiBub3QgdmFsaWRhdGVkIiAmIHRocmVzaG9sZF9xdmFsdWVfZGlyZWN0aW9uYWwgPT0gImluc2lnbmlmaWNhbnQiIH4gImluc2lnbmlmaWNhbnQiKSwKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdGhyZXNob2xkXzI1X3F2YWx1ZV9jb2hvcnRfY29tcGFyaXNvbiA9IGZhY3Rvcih0aHJlc2hvbGRfMjVfcXZhbHVlX2NvaG9ydF9jb21wYXJpc29uLCBsZXZlbHM9YygiaW5zaWduaWZpY2FudCIsICJzaWduaWZpY2FudCIsICJzaWduaWZpY2FudCBhbmQgdmFsaWRhdGVkIikpKQoKbGltPTcwCnA2NiA8LSBjb21wYXJlX2Rpc2NvdmVyeV92YWxpZGF0aW9uICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBtZXRoLmRpZmYudGFyZ2V0ZWQudmFsaWRhdGlvbiwgeSA9IG1ldGguZGlmZi5XR0JTLnJhdywgY29sb3VyPXRocmVzaG9sZF8yNV9xdmFsdWVfY29ob3J0X2NvbXBhcmlzb24pKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDE2LCBhbHBoYT0wLjYsIHNpemU9MSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTI1LCAyNSksIGxpbmV0eXBlPSJkb3R0ZWQiKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC0yNSwgMjUpLCBsaW5ldHlwZT0iZG90dGVkIikrCiAgeWxhYigiXHUwMzk0IE1ldGh5bGF0aW9uIFslXVxuV0dCUyBEaXNjb3ZlcnkgQ29ob3J0IikgKwogIHhsYWIoIlx1MDM5NCBNZXRoeWxhdGlvbiBbJV1cblRhcmdldGVkIFNlcXVlbmNpbmcgVmFsaWRhdGlvbiBDb2hvcnQiKSArCiAgI2xhYnModGl0bGUgPSAiTG9nLUJhY2t0cmFuc2Zvcm1lZCwgUXVhbnRpbGUgTm9ybWFsaXNlZCBhbmQgQ29tQmF0IiwgCiAgbGFicyhjb2xvdXI9IkRNUiIpICsKICBzdGF0X2NvcihsYWJlbC54ID0oLTU1KSAsIGxhYmVsLnk9YygtMTAsIDAsIDEwKSwgbWV0aG9kPSJwZWFyc29uIiwgc2l6ZT0yLjUpKwogIHRoZW1lX1B1YmxpY2F0aW9uKCkrCiAgeWxpbSgtbGltLCBsaW0pICsKICB4bGltKC1saW0sIGxpbSkgKwogIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpKSsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiM5MTk0OTQiLCAia2hha2kzICIsICJ0YW40IiksIGd1aWRlID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMuNSwgYWxwaGE9MSkgKSkrCiAgZmFjZXRfd3JhcCh2YXJzKGNvbmRpdGlvbikpCnA2NgpgYGAKCmBgYHtyIE51bWJlcl9vZl9WYWxpZGF0ZWRfVGlsZXNfVmFsaWRhdGlvbl9Db2hvcnR9CmNvaG9ydF9jb21wYXJpc29uX3ZhbGlkYXRpb25fbnVtYmVyc19xX3ZhbHVlX2RpcmVjdGlvbmFsIDwtIGNvbXBhcmVfZGlzY292ZXJ5X3ZhbGlkYXRpb24gJT4lCiAgZ3JvdXBfYnkoY29uZGl0aW9uKSAlPiUgCiAgZHBseXI6OmNvdW50KHRocmVzaG9sZF9xdmFsdWVfZGlyZWN0aW9uYWwgPT0ic2lnbmlmaWNhbnQiKSAlPiUgCiAgZHBseXI6OnJlbmFtZSh0aHJlc2hvbGRfcV92YWx1ZV9kaXJlY3Rpb25hbD0yKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbT10aHJlc2hvbGRfcV92YWx1ZV9kaXJlY3Rpb25hbCwgdmFsdWVzX2Zyb209bikgJT4lIAogIGRwbHlyOjpyZW5hbWUoU2lnbmlmaWNhbnRfRE1SPTMsIEluc2lnbmlmaWNhbnRfRE1SPTIpICU+JSAKICBtdXRhdGUoUGVyY2VudGFnZV9TaWduaWZpY2FudF9ETVI9KFNpZ25pZmljYW50X0RNUi8oSW5zaWduaWZpY2FudF9ETVIrU2lnbmlmaWNhbnRfRE1SKSoxMDApLCAKICAgICAgICAgVG90YWxfTnVtYmVyX0RNUnM9c3VtKFNpZ25pZmljYW50X0RNUiwgSW5zaWduaWZpY2FudF9ETVIpKSAlPiUgCiAgZHBseXI6OnJlbG9jYXRlKFRvdGFsX051bWJlcl9ETVJzLCAuYWZ0ZXI9Y29uZGl0aW9uKQoKY29ob3J0X2NvbXBhcmlzb25fdmFsaWRhdGlvbl9udW1iZXJzX3FfdmFsdWVfMjVfY3V0b2ZmIDwtIGNvbXBhcmVfZGlzY292ZXJ5X3ZhbGlkYXRpb24gJT4lCiAgZHBseXI6OmZpbHRlcih0aHJlc2hvbGRfcXZhbHVlID09ICJzaWduaWZpY2FudCIpICU+JSAKICBncm91cF9ieShjb25kaXRpb24pICU+JQogIGRwbHlyOjpjb3VudCh0aHJlc2hvbGRfMjVfY29ob3J0X2NvbXBhcmlzb24gPT0gIkRNUiB2YWxpZGF0ZWQiICYgdGhyZXNob2xkX3F2YWx1ZSA9PSAic2lnbmlmaWNhbnQiKSAlPiUgCiAgZHBseXI6OnJlbmFtZSh0aHJlc2hvbGRfMjU9MikgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb209dGhyZXNob2xkXzI1LCB2YWx1ZXNfZnJvbT1uKSAlPiUKICBkcGx5cjo6cmVuYW1lKFNpZ25pZmljYW50X0RNUl9WYWxpZGF0ZWQ9MywgU2lnbmlmaWNhbnRfRE1SX05vdF9WYWxpZGF0ZWQ9MikgJT4lCiAgbXV0YXRlKFBlcmNlbnRhZ2VfU2lnbmlmaWNhbnRfRE1SX1ZhbGlkYXRlZD0oU2lnbmlmaWNhbnRfRE1SX1ZhbGlkYXRlZC8oU2lnbmlmaWNhbnRfRE1SX05vdF9WYWxpZGF0ZWQrU2lnbmlmaWNhbnRfRE1SX1ZhbGlkYXRlZCkqMTAwKSwgCiAgICAgICAgIFRvdGFsX051bWJlcl9ETVJzPXN1bShTaWduaWZpY2FudF9ETVJfTm90X1ZhbGlkYXRlZCwgU2lnbmlmaWNhbnRfRE1SX1ZhbGlkYXRlZCkpICU+JSAKICBkcGx5cjo6cmVsb2NhdGUoVG90YWxfTnVtYmVyX0RNUnMsIC5hZnRlcj1jb25kaXRpb24pCgpjb2hvcnRfY29tcGFyaXNvbl92YWxpZGF0aW9uX251bWJlcnNfcV92YWx1ZV9kaXJlY3Rpb25hbF8yNV9jdXRvZmYgPC0gY29tcGFyZV9kaXNjb3ZlcnlfdmFsaWRhdGlvbiAlPiUKICBkcGx5cjo6ZmlsdGVyKHRocmVzaG9sZF9xdmFsdWVfZGlyZWN0aW9uYWwgPT0gInNpZ25pZmljYW50IikgJT4lIAogIGdyb3VwX2J5KGNvbmRpdGlvbikgJT4lCiAgZHBseXI6OmNvdW50KHRocmVzaG9sZF8yNV9jb2hvcnRfY29tcGFyaXNvbiA9PSAiRE1SIHZhbGlkYXRlZCIgJiB0aHJlc2hvbGRfcXZhbHVlID09ICJzaWduaWZpY2FudCIpICU+JSAKICBkcGx5cjo6cmVuYW1lKHRocmVzaG9sZF8yNT0yKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbT10aHJlc2hvbGRfMjUsIHZhbHVlc19mcm9tPW4pICU+JQogIGRwbHlyOjpyZW5hbWUoU2lnbmlmaWNhbnRfRE1SX1ZhbGlkYXRlZD0zLCBTaWduaWZpY2FudF9ETVJfTm90X1ZhbGlkYXRlZD0yKSAlPiUKICBtdXRhdGUoUGVyY2VudGFnZV9TaWduaWZpY2FudF9ETVJfVmFsaWRhdGVkPShTaWduaWZpY2FudF9ETVJfVmFsaWRhdGVkLyhTaWduaWZpY2FudF9ETVJfTm90X1ZhbGlkYXRlZCtTaWduaWZpY2FudF9ETVJfVmFsaWRhdGVkKSoxMDApLCAKICAgICAgICAgVG90YWxfTnVtYmVyX0RNUnM9c3VtKFNpZ25pZmljYW50X0RNUl9Ob3RfVmFsaWRhdGVkLCBTaWduaWZpY2FudF9ETVJfVmFsaWRhdGVkKSkgJT4lIAogIGRwbHlyOjpyZWxvY2F0ZShUb3RhbF9OdW1iZXJfRE1ScywgLmFmdGVyPWNvbmRpdGlvbikKCgpwcmludChjb2hvcnRfY29tcGFyaXNvbl92YWxpZGF0aW9uX251bWJlcnNfcV92YWx1ZV9kaXJlY3Rpb25hbCkKcHJpbnQoY29ob3J0X2NvbXBhcmlzb25fdmFsaWRhdGlvbl9udW1iZXJzX3FfdmFsdWVfMjVfY3V0b2ZmKQpwcmludChjb2hvcnRfY29tcGFyaXNvbl92YWxpZGF0aW9uX251bWJlcnNfcV92YWx1ZV9kaXJlY3Rpb25hbF8yNV9jdXRvZmYpCmBgYAoKIyMjIyBDb3JyZWxhdGUgVmFsaWRhdGVkIERNUnMgdG8gQ2xpbmljYWwgTWFya2VycwpUbyBmaW5kIG91dCBpZiBETVIgdmFsaWRhdGlvbiBtaWdodCBiZSBhc3NvY2lhYmxlIHdpdGggY2xpbmljYWwgbWFya2VyIGV4cHJlc3Npb24KYGBge3IgQ29ycmVsYXRlX1ZhbGlkYXRlZF9ETVJzX3RvX0NsaW5pY2FsIE1hcmtlcnNfbm9ybWFsaXNlZF9wZXJjX21ldGh9CiNGaXJzdCB0cnkgdG8gdXNlIHF1YW50aWxlIGFuZCBjb21iYXQgbm9ybWFsaXNlZCBwZXJjX21ldGggdmFsdWVzOgoKCkRNUnMgPC0gY29tcGFyZV9kaXNjb3ZlcnlfdmFsaWRhdGlvbiAlPiUgCiAgZHBseXI6OnNlbGVjdChjaHJvbSwgc3RhcnQsIGVuZCwgY29uZGl0aW9uLCB0aHJlc2hvbGRfMjVfY29ob3J0X2NvbXBhcmlzb24pICU+JSAKICB0aWR5cjo6dW5pdGUoRE1SLCBjaHJvbSwgc3RhcnQsIGVuZCwgc2VwPSIuIikgJT4lIAogIGdyb3VwX3NwbGl0KHRocmVzaG9sZF8yNV9jb2hvcnRfY29tcGFyaXNvbikgJT4lIAogIG1hcCh+cHVsbCguLCBETVIpICU+JSB1bmlxdWUoKSkKCiNKb2luIHdpdGggY2xpbmljYWwgRGF0YQpvdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9ub19sb2dfcGxvdF9jbGluaWNhbF9kYXRhPC1vdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9ub19sb2dfcGxvdCAlPiUgCiAgZHBseXI6OnNlbGVjdChzYW1wbGVfaWRzLCBzdGFydHNfd2l0aCgiY2hyIikpICU+JSAKICBkcGx5cjo6aW5uZXJfam9pbihjbGluaWNhbF9tYXJrZXJzX0FDUywgYnkgPSBjKCJzYW1wbGVfaWRzIj0iU2FtcGxlIikpCgojQ2FsY3VsYXRlIENvcnJlbGF0aW9uCnZhbGlkYXRpb25fY29ycl9iaW9tYXJrZXJzIDwtIG92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0X25vX2xvZ19wbG90X2NsaW5pY2FsX2RhdGEgJT4lIAogIGRwbHlyOjpzZWxlY3QoYW55X29mKGMoRE1Sc1tbMV1dLCBETVJzW1syXV0pKSwgIkxWRUYoJSkiLCAiQ1JQKG1nL2RsXzw1KSIsIlRyb3BvbmluVGhzX3QxIChuZy9sIDwxNG9yPDUwKSIsICJDSyAoVS9sIF88MTkwKSIgLCAiQ0ttYXgoVS9sXzwxOTApIiAsIkNLLU1CKFUvbCA8MjQpIiwiQ0stTUJfTWF4IikgJT4lIAogIHN0YXRzOjpjb3IodXNlID0gImNvbXBsZXRlLm9icyIsbWV0aG9kID0gInBlYXJzb24iKSAlPiUKICBhc190aWJibGUocm93bmFtZXM9IkRNUiIpICU+JSAKICBkcGx5cjo6bXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfi5eMikpICU+JSAKICBkcGx5cjo6c2VsZWN0KERNUiwgIkxWRUYoJSkiLCAiQ1JQKG1nL2RsXzw1KSIsIlRyb3BvbmluVGhzX3QxIChuZy9sIDwxNG9yPDUwKSIsICJDSyAoVS9sIF88MTkwKSIgLCAiQ0ttYXgoVS9sXzwxOTApIiAsIkNLLU1CKFUvbCA8MjQpIiwiQ0stTUJfTWF4IikKCiNBbm5vdGF0ZSB3aXRoIHZhbGlkYXRpb24gc3RhdHVzCnZhbGlkYXRpb25fY29ycl9iaW9tYXJrZXJzIDwtIHZhbGlkYXRpb25fY29ycl9iaW9tYXJrZXJzICU+JSAKICBkcGx5cjo6bXV0YXRlKERNUnNfdmFsaWRhdGlvbj1pZl9lbHNlKERNUiAlaW4lIERNUnNbWzJdXSwgInZhbGlkYXRlZCIsICJub3QgdmFsaWRhdGVkIikpCgp2YWxpZGF0aW9uX2NvcnJfYmlvbWFya2Vyc19sb25nIDwtIHZhbGlkYXRpb25fY29ycl9iaW9tYXJrZXJzICU+JQogIGRwbHlyOjpyZW5hbWUoJ0NSUCAobWcvZGwpJz0gIkNSUChtZy9kbF88NSkiLCAKICAgICAgICAgICAgICAgICdUcm9wb25pblQgKG5nL2wpJz0iVHJvcG9uaW5UaHNfdDEgKG5nL2wgPDE0b3I8NTApIiwKICAgICAgICAgICAgICAgICdDSyAoVS9sKSc9IkNLIChVL2wgXzwxOTApIiwKICAgICAgICAgICAgICAgICdDSyBtYXggKFUvbCknPSJDS21heChVL2xfPDE5MCkiLAogICAgICAgICAgICAgICAgJ0NLLU1CIChVL2wpJz0iQ0stTUIoVS9sIDwyNCkiLAogICAgICAgICAgICAgICAgJ0NLLU1CIG1heCAoVS9sKSc9IkNLLU1CX01heCIpICU+JSAKICB0aWR5cjo6cGl2b3RfbG9uZ2VyKC1jKERNUiwgRE1Sc192YWxpZGF0aW9uKSwgbmFtZXNfdG8gPSAiYmlvbWFya2VyIiwgdmFsdWVzX3RvPSJSc3F1YXJlZCIpCgojUGxvdApjbGluaWNhbF9tYXJrZXJfY29ycmVsYXRpb24gPC0gdmFsaWRhdGlvbl9jb3JyX2Jpb21hcmtlcnNfbG9uZyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gRE1Sc192YWxpZGF0aW9uLCB5ID0gUnNxdWFyZWQsIGZpbGw9RE1Sc192YWxpZGF0aW9uKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNpemU9MC4zKSArCiAgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMoc2l6ZT0yLCBsYWJlbC54PTEuMiwgbGFiZWwueT0xLjEpKyAgCiAgbGFicyh5PWV4cHJlc3Npb24oIlIiXjIpLCB4PSJETVJzIikgKwogIHlsaW0oMCwxLjI1KSsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSAiRE1ScyIsIHZhbHVlcz1jKCJkYXJrcmVkIiwgImRhcmtncmVlbiIpKSArCiAgdGhlbWVfYncoKSsKICBmYWNldF93cmFwKHZhcnMoYmlvbWFya2VyKSkrCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT02KSkKCmNsaW5pY2FsX21hcmtlcl9jb3JyZWxhdGlvbgoKIyBnZ3NhdmUoYmcgPSJ3aGl0ZSIsCiMgIi9ob21lL2FyYXRoZ2Uvb3V0cHV0L3Bsb3RzL0FDU1NfY2FyZGlhY19jY2ZETkEvY2xpbmljYWxfbWFya2VyX2NvcnJlbGF0aW9uLnRpZmYiLAojIGRldmljZSA9ICJ0aWZmIiwKIyBwbG90ID0gY2xpbmljYWxfbWFya2VyX2NvcnJlbGF0aW9uCiMgKQpgYGAKCgpgYGB7ciBDb3JyZWxhdGVfVmFsaWRhdGVkX0RNUnNfdG9fQ2xpbmljYWwgTWFya2Vyc19yYXdfcGVyY19tZXRofQojIFRyeSBhbHNvIHdpdGggdW5ub3JtYWxpc2VkIHJhdyBwZXJjX21ldGggdmFsdWVzOgoKI1RyYW5zcG9zZSB0aWJibGUKb3ZlcmxhcF90aWxlc192YWxpZGF0aW9uX1dHQlNfdCA8LSBvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCUyAlPiUgCiAgcGl2b3RfbG9uZ2VyKC10aWxlcykgJT4lICAgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRpbGVzLCB2YWx1ZXNfZnJvbSA9IHZhbHVlKSAlPiUgCiAgZHBseXI6OnJlbmFtZShzYW1wbGVfaWRzPSJuYW1lIikKCiNKb2luIHdpdGggQ2xpbmljYWwgRGF0YQpvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCU190X2NsaW5pY2FsX2RhdGE8LW92ZXJsYXBfdGlsZXNfdmFsaWRhdGlvbl9XR0JTX3QgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlX2lkcywgc3RhcnRzX3dpdGgoImNociIpKSAlPiUgCiAgZHBseXI6OmlubmVyX2pvaW4oY2xpbmljYWxfbWFya2Vyc19BQ1MsIGJ5ID0gYygic2FtcGxlX2lkcyI9IlNhbXBsZSIpKQoKI0NhbGN1bGF0ZSBDb3JyZWxhdGlvbgp2YWxpZGF0aW9uX2NvcnJfYmlvbWFya2Vyc19yYXdfZGF0YSA8LSBvdmVybGFwX3RpbGVzX3ZhbGlkYXRpb25fV0dCU190X2NsaW5pY2FsX2RhdGEgJT4lIAogIGRwbHlyOjpzZWxlY3QoYW55X29mKGMoRE1Sc1tbMV1dLCBETVJzW1syXV0pKSwgIkxWRUYoJSkiLCAiQ1JQKG1nL2RsXzw1KSIsIlRyb3BvbmluVGhzX3QxIChuZy9sIDwxNG9yPDUwKSIsICJDSyAoVS9sIF88MTkwKSIgLCAiQ0ttYXgoVS9sXzwxOTApIiAsIkNLLU1CKFUvbCA8MjQpIiwiQ0stTUJfTWF4IikgJT4lIAogIHN0YXRzOjpjb3IodXNlID0gImNvbXBsZXRlLm9icyIsbWV0aG9kID0gInBlYXJzb24iKSAlPiUKICBhc190aWJibGUocm93bmFtZXM9IkRNUiIpICU+JSAKICBkcGx5cjo6bXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfi5eMikpICU+JSAKICBkcGx5cjo6c2VsZWN0KERNUiwgIkxWRUYoJSkiLCAiQ1JQKG1nL2RsXzw1KSIsIlRyb3BvbmluVGhzX3QxIChuZy9sIDwxNG9yPDUwKSIsICJDSyAoVS9sIF88MTkwKSIgLCAiQ0ttYXgoVS9sXzwxOTApIiAsIkNLLU1CKFUvbCA8MjQpIiwiQ0stTUJfTWF4IikKCiNBbm5vdGF0ZSB3aXRoIHZhbGlkYXRpb24gc3RhdHVzCnZhbGlkYXRpb25fY29ycl9iaW9tYXJrZXJzX3Jhd19kYXRhIDwtIHZhbGlkYXRpb25fY29ycl9iaW9tYXJrZXJzX3Jhd19kYXRhICU+JSAKICBkcGx5cjo6bXV0YXRlKERNUnNfdmFsaWRhdGlvbj1pZl9lbHNlKERNUiAlaW4lIERNUnNbWzJdXSwgInZhbGlkYXRlZCIsICJub3QgdmFsaWRhdGVkIikpCgp2YWxpZGF0aW9uX2NvcnJfYmlvbWFya2Vyc19yYXdfZGF0YV9sb25nIDwtIHZhbGlkYXRpb25fY29ycl9iaW9tYXJrZXJzX3Jhd19kYXRhICU+JQogIGRwbHlyOjpyZW5hbWUoJ0NSUCAobWcvZGwpJz0gIkNSUChtZy9kbF88NSkiLCAKICAgICAgICAgICAgICAgICdUcm9wb25pblQgKG5nL2wpJz0iVHJvcG9uaW5UaHNfdDEgKG5nL2wgPDE0b3I8NTApIiwKICAgICAgICAgICAgICAgICdDSyAoVS9sKSc9IkNLIChVL2wgXzwxOTApIiwKICAgICAgICAgICAgICAgICdDSyBtYXggKFUvbCknPSJDS21heChVL2xfPDE5MCkiLAogICAgICAgICAgICAgICAgJ0NLLU1CIChVL2wpJz0iQ0stTUIoVS9sIDwyNCkiLAogICAgICAgICAgICAgICAgJ0NLLU1CIG1heCAoVS9sKSc9IkNLLU1CX01heCIpICU+JSAKICB0aWR5cjo6cGl2b3RfbG9uZ2VyKC1jKERNUiwgRE1Sc192YWxpZGF0aW9uKSwgbmFtZXNfdG8gPSAiYmlvbWFya2VyIiwgdmFsdWVzX3RvPSJSc3F1YXJlZCIpCgojUGxvdApjbGluaWNhbF9tYXJrZXJfY29ycmVsYXRpb25fcmF3X2RhdGEgPC0gdmFsaWRhdGlvbl9jb3JyX2Jpb21hcmtlcnNfcmF3X2RhdGFfbG9uZyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gRE1Sc192YWxpZGF0aW9uLCB5ID0gUnNxdWFyZWQsIGZpbGw9RE1Sc192YWxpZGF0aW9uKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNpemU9MC4zKSArCiAgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMoc2l6ZT0yLCBsYWJlbC54PTEuMiwgbGFiZWwueT0xLjEpKyAgCiAgbGFicyh5PWV4cHJlc3Npb24oIlIiXjIpLCB4PSJETVJzIikgKwogIHlsaW0oMCwxLjI1KSsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSAiRE1ScyIsIHZhbHVlcz1jKCJkYXJrcmVkIiwgImRhcmtncmVlbiIpKSArCiAgdGhlbWVfYncoKSsKICBmYWNldF93cmFwKHZhcnMoYmlvbWFya2VyKSkrCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT02KSkKCmNsaW5pY2FsX21hcmtlcl9jb3JyZWxhdGlvbl9yYXdfZGF0YQoKIyBnZ3NhdmUoYmcgPSJ3aGl0ZSIsCiMgIi9ob21lL2FyYXRoZ2Uvb3V0cHV0L3Bsb3RzL0FDU1NfY2FyZGlhY19jY2ZETkEvY2xpbmljYWxfbWFya2VyX2NvcnJlbGF0aW9uX3Jhd19kYXRhLnRpZmYiLAojIGRldmljZSA9ICJ0aWZmIiwKIyBwbG90ID0gY2xpbmljYWxfbWFya2VyX2NvcnJlbGF0aW9uX3Jhd19kYXRhCiMgKQpgYGAKCiMjIyBDb3ZlcmFnZSB3ZWlnaHRlZCAlTWV0aHlsYXRpb24gZm9yIENvbUJhdCB3aXRoIFF1YW50aWxlIE5vcm1hbGlzYXRpb24KYGBge3IgQ2FsY3VsYXRlX2NvdmVyYWdlX3dlaWdodGVkX3BlcmNfbWV0aCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbWV0aENvdlBlckJhc2VXR0JTIDwtIHNldE5hbWVzKG1ldGh5bEtpdDo6Z2V0RGF0YShtZXRoeWxCYXNlREJfV0dCU19hbGxfc2FtcGxlcylbLCBjKDEsIDIsIDMsIG1ldGh5bEJhc2VEQl9XR0JTX2FsbF9zYW1wbGVzQGNvdmVyYWdlLmluZGV4KV0sIGMoImNociIsICJzdGFydCIsICJlbmQiLCBtZXRoeWxCYXNlREJfV0dCU19hbGxfc2FtcGxlc0BzYW1wbGUuaWRzKSkKbWV0aENvdlBlckJhc2VUYXJnZXRlZCA8LSBzZXROYW1lcyhtZXRoeWxLaXQ6OmdldERhdGEobWV0aHlsQmFzZURCX3ZhbGlkYXRpb25fbm9fQ0FEKVssIGMoMSwgMiwgMywgbWV0aHlsQmFzZURCX3ZhbGlkYXRpb25fbm9fQ0FEQGNvdmVyYWdlLmluZGV4KV0sIGMoImNociIsICJzdGFydCIsICJlbmQiLCBtZXRoeWxCYXNlREJfdmFsaWRhdGlvbl9ub19DQURAc2FtcGxlLmlkcykpCiNkZXRhY2goInBhY2thZ2U6bWV0aHlsS2l0IiwgdW5sb2FkID0gVFJVRSkKI2RldGFjaCgicGFja2FnZTpHZW5vbWljUmFuZ2VzIiwgdW5sb2FkID0gVFJVRSkKCm1ldGhDb3ZQZXJCYXNlV0dCUyA8LSBtZXRoQ292UGVyQmFzZVdHQlMgJT4lCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCBjaHIsIHN0YXJ0LCBlbmQsIHNlcCA9ICIuIikgJT4lCiAgZHBseXI6OmZpbHRlcih0aWxlcyAlaW4lIGModGlsZXMpKQoKbWV0aENvdlBlckJhc2VUYXJnZXRlZCA8LSBtZXRoQ292UGVyQmFzZVRhcmdldGVkICU+JQogIHRpZHlyOjp1bml0ZSh0aWxlcywgY2hyLCBzdGFydCwgZW5kLCBzZXAgPSAiLiIpICU+JQogIGRwbHlyOjpmaWx0ZXIodGlsZXMgJWluJSBjKHRpbGVzKSkKCgptZXRoQ292UGVyQmFzZSA8LSBtZXRoQ292UGVyQmFzZVdHQlMgJT4lIGlubmVyX2pvaW4obWV0aENvdlBlckJhc2VUYXJnZXRlZCkKbWV0aENvdlBlckJhc2UgPC0gbWV0aENvdlBlckJhc2UgJT4lIHBpdm90X2xvbmdlcigtdGlsZXMsIG5hbWVzX3RvID0gInNhbXBsZV9pZHMiLCB2YWx1ZXNfdG8gPSAiY292ZXJhZ2UiKQoKYWxsX2RhdGFfY292ZXJhZ2UgPC0gYWxsX2RhdGEgJT4lIGxlZnRfam9pbihtZXRoQ292UGVyQmFzZSwgYnkgPSBjKCJ0aWxlcyIsICJzYW1wbGVfaWRzIikpCkRNX2RhdGFfY292ZXJhZ2UgPC0gYWxsX2RhdGFfY292ZXJhZ2UgJT4lCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCB0aWxlcywgY29uZGl0aW9uLCBzZXAgPSAiLiIpICU+JQogIGZpbHRlcih0aWxlcyAlaW4lIGRpZmZfbWV0aF90aWxlcykgJT4lCiAgdGlkeXI6OnNlcGFyYXRlKHRpbGVzLCBpbnRvID0gYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiwgImNvbmRpdGlvbiIpKQpgYGAKCmBgYHtyIFdlaWdodGluZ19NZWFuX0RpZmZlcmVuY2Vfb2ZfUXVhbnRpbGVfTm9ybWFsaXNlZF9Db21iYXRfRGF0YV9BZnRlcl9CYWNrdHJhbnNmb3JtYXRpb259Cm92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0X25vX2xvZ193ZWlnaHRlZCA8LSBvdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9ub19sb2cgJT4lIGxlZnRfam9pbihkcGx5cjo6c2VsZWN0KGFsbF9kYXRhX2NvdmVyYWdlLCB0aWxlcywgc2FtcGxlX2lkcywgY292ZXJhZ2UpLCBieSA9IGMoInRpbGVzIiwgInNhbXBsZV9pZHMiKSkKCmNhbGNfd2VpZ2h0ZWRfZGlmZl9vZl9tZWFucyA8LSBmdW5jdGlvbihkYXRhZnJhbWVfYWxsX3NhbXBsZXMpIHsKICBkYXRhZnJhbWVfYWxsX3NhbXBsZXNfbWVhbiA8LSBkYXRhZnJhbWVfYWxsX3NhbXBsZXMgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkodGlsZXMsIHNlcV9tZXRob2QsIGNvbmRpdGlvbikgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXNlKHdlaWdodGVkX21lYW4gPSB3ZWlnaHRlZC5tZWFuKHBlcmNfbWV0aCwgY292ZXJhZ2UpKQoKICBkYXRhZnJhbWVfYWxsX3NhbXBsZXNfbWVhbl9kaWZmIDwtIGRhdGFmcmFtZV9hbGxfc2FtcGxlc19tZWFuICU+JQogICAgcGl2b3Rfd2lkZXIodmFsdWVzX2Zyb20gPSB3ZWlnaHRlZF9tZWFuLCBuYW1lc19mcm9tID0gY29uZGl0aW9uKSAlPiUKICAgIG11dGF0ZSgKICAgICAgbWV0aC5kaWZmX1NURU1JID0gU1RFTUkgLSBDb250cm9sLAogICAgICBtZXRoLmRpZmZfTlNURU1JID0gTlNURU1JIC0gQ29udHJvbCwKICAgICAgbWV0aC5kaWZmX1VBID0gVUEgLSBDb250cm9sCiAgICApICU+JQogICAgZHBseXI6OnNlbGVjdCgtYyhDb250cm9sLCBOU1RFTUksIFNURU1JLCBVQSkpICU+JQogICAgZHBseXI6OnJlbmFtZShTVEVNSSA9ICJtZXRoLmRpZmZfU1RFTUkiLCBOU1RFTUkgPSAibWV0aC5kaWZmX05TVEVNSSIsIFVBID0gIm1ldGguZGlmZl9VQSIpICU+JQogICAgcGl2b3RfbG9uZ2VyKC1jKHRpbGVzLCBzZXFfbWV0aG9kKSwKICAgICAgbmFtZXNfdG8gPSAiY29uZGl0aW9uIiwKICAgICAgdmFsdWVzX3RvID0gIndlaWdodGVkX21ldGhfZGlmZiIKICAgICkgJT4lCiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gInNlcV9tZXRob2QiLCB2YWx1ZXNfZnJvbSA9ICJ3ZWlnaHRlZF9tZXRoX2RpZmYiKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUod2VpZ2h0ZWQubWV0aC5kaWZmLldHQlMgPSAiV0dCUyIsIHdlaWdodGVkLm1ldGguZGlmZi50YXJnZXRlZCA9ICJ0YXJnZXRlZCIpCn0KCm92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0X25vX2xvZ193ZWlnaHRlZCA8LSBjYWxjX3dlaWdodGVkX2RpZmZfb2ZfbWVhbnMob3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nX3dlaWdodGVkKQoKb3ZlcmxhcF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ193ZWlnaHRlZCA8LSBvdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9ub19sb2dfd2VpZ2h0ZWQgJT4lCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCB0aWxlcywgY29uZGl0aW9uLCBzZXAgPSAiLiIpICU+JQogIGRwbHlyOjpmaWx0ZXIodGlsZXMgJWluJSBjKGRpZmZfbWV0aF90aWxlcykpICU+JQogIHRpZHlyOjpzZXBhcmF0ZSh0aWxlcywgaW50byA9IGMoImNocm9tIiwgInN0YXJ0IiwgImVuZCIsICJjb25kaXRpb24iKSwgc2VwID0gIlxcLiIpICU+JSAKICB0aWR5cjo6dW5pdGUodGlsZXMsIGNocm9tLCBzdGFydCwgZW5kLCBzZXA9Ii4iKQpgYGAKCmBgYHtyIFBsb3Rfd2VpZ2h0ZWRfZGlmZmVyZW5jZV9vZl9tZWFuc19hZnRlcl9xdWFudGlsZV9ub3JtYWxpc2F0aW9uX2NvbWJhdF9hbmRfYmFja3RyYW5zZm9ybWF0aW9uLCBmaWcuZGltID0gYygxMCwxMCl9CiNDYWxjdWxhdGUgdGhyZXNob2xkIApvdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9ub19sb2dfd2VpZ2h0ZWQgPC0gb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nX3dlaWdodGVkICU+JSAKICBtdXRhdGUodGhyZXNob2xkXzI1PSBjYXNlX3doZW4oKCgoMjUgPD0gd2VpZ2h0ZWQubWV0aC5kaWZmLldHQlMpICYgKDI1IDw9IHdlaWdodGVkLm1ldGguZGlmZi50YXJnZXRlZCkpICB8ICgoKHdlaWdodGVkLm1ldGguZGlmZi50YXJnZXRlZCA8PS0yNSkgJiAod2VpZ2h0ZWQubWV0aC5kaWZmLldHQlMgPD0tMjUpKSkgKSB+ICJ8MjUlfCIsIFRSVUUgfiAibm90IGluIHJhbmdlIikpCgpvdmVybGFwX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3dlaWdodGVkIDwtIG92ZXJsYXBfRE1fbG9nX25vcm1hbGlzZWRfY29tYmF0X2xvZ19mb2xkX2NoYW5nZV9ub19sb2dfd2VpZ2h0ZWQgJT4lIAogIG11dGF0ZSh0aHJlc2hvbGRfMjU9IGNhc2Vfd2hlbigoKCgyNSA8PSB3ZWlnaHRlZC5tZXRoLmRpZmYuV0dCUykgJiAoMjUgPD0gd2VpZ2h0ZWQubWV0aC5kaWZmLnRhcmdldGVkKSkgIHwgKCgod2VpZ2h0ZWQubWV0aC5kaWZmLnRhcmdldGVkIDw9LTI1KSAmICh3ZWlnaHRlZC5tZXRoLmRpZmYuV0dCUyA8PS0yNSkpKSApIH4gInwyNSV8IiwgVFJVRSB+ICJub3QgaW4gcmFuZ2UiKSkKCiNDb3VudCBob3cgbWFueSB0aWxlcyBhcmUgYWJvdmUvYmVsb3cgdGhyZXNob2xkIGZvciBlYWNoIGNvbmRpdGlvbgpvdmVybGFwX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9ub19sb2dfd2VpZ2h0ZWRfdmFsaWRhdGVkIDwtIG92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0X25vX2xvZ193ZWlnaHRlZCAlPiUgCiAgZHBseXI6Omdyb3VwX2J5KGNvbmRpdGlvbikgJT4lIAogIGRwbHlyOjpjb3VudCh0aHJlc2hvbGRfMjUgPT0ifDI1JXwiKSAlPiUgCiAgZHBseXI6OnJlbmFtZSh0aHJlc2hvbGRfMjU9MikgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb209dGhyZXNob2xkXzI1LCB2YWx1ZXNfZnJvbT1uKSAlPiUKICBkcGx5cjo6cmVuYW1lKFZhbGlkYXRlZD0zLCBOb3RfVmFsaWRhdGVkPTIpICU+JSAKICBtdXRhdGUocGVyY2VudGFnZT0oVmFsaWRhdGVkLyhOb3RfVmFsaWRhdGVkK1ZhbGlkYXRlZCkqMTAwKSkKCnByaW50KG92ZXJsYXBfbG9nX25vcm1hbGlzZWRfY29tYmF0X25vX2xvZ193ZWlnaHRlZF92YWxpZGF0ZWQpCgpvdmVybGFwX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3dlaWdodGVkX3ZhbGlkYXRlZCA8LSBvdmVybGFwX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3dlaWdodGVkICU+JSAgIAogIGRwbHlyOjpncm91cF9ieShjb25kaXRpb24pICU+JSAKICBkcGx5cjo6Y291bnQodGhyZXNob2xkXzI1ID09InwyNSV8IikgJT4lIAogIGRwbHlyOjpyZW5hbWUodGhyZXNob2xkXzI1PTIpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tPXRocmVzaG9sZF8yNSwgdmFsdWVzX2Zyb209bikgJT4lIAogIGRwbHlyOjpyZW5hbWUoVmFsaWRhdGVkPTMsIE5vdF9WYWxpZGF0ZWQ9MikgJT4lIAogIG11dGF0ZShwZXJjZW50YWdlPShWYWxpZGF0ZWQvKE5vdF9WYWxpZGF0ZWQrVmFsaWRhdGVkKSoxMDApKQoKcHJpbnQob3ZlcmxhcF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ193ZWlnaHRlZF92YWxpZGF0ZWQpCgpwNTAgPC0gb3ZlcmxhcF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbm9fbG9nX3dlaWdodGVkICU+JQogIGdncGxvdChhZXMoeCA9IHdlaWdodGVkLm1ldGguZGlmZi50YXJnZXRlZCwgeSA9IHdlaWdodGVkLm1ldGguZGlmZi5XR0JTLCBjb2xvdXI9dGhyZXNob2xkXzI1KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAxNiwgYWxwaGE9MC42LCBzaXplPTIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0yNSwgMjUpLCBsaW5ldHlwZT0iZG90dGVkIikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygtMjUsIDI1KSwgbGluZXR5cGU9ImRvdHRlZCIpKwogIHlsYWIoIldlaWdodGVkIE1lYW4gTWV0aHlsYXRpb24gRGlmZmVyZW5jZSBXR0JTIikgKwogIHhsYWIoIldlaWdodGVkIE1lYW4gTWV0aHlsYXRpb24gRGlmZmVyZW5jZSBUYXJnZXRlZCBTZXF1ZW5jaW5nIikgKwogIGxhYnModGl0bGUgPSAiQWxsIENvbW1vbiBUaWxlcyIsIGNvbG91cj0iVGhyZXNob2xkIikgKwogIHN0YXRfY29yKG1ldGhvZD0icGVhcnNvbiIpKyAKICB4bGltKC05MCwgOTApICsKICB5bGltKC05MCwgOTApICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiM5MTk0OTQiLCAiIzdDQUUwMCIpKSsKICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGNvbmRpdGlvbikpCgpwNTEgPC0gb3ZlcmxhcF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ193ZWlnaHRlZCAlPiUKICBnZ3Bsb3QoYWVzKHggPSB3ZWlnaHRlZC5tZXRoLmRpZmYudGFyZ2V0ZWQsIHkgPSB3ZWlnaHRlZC5tZXRoLmRpZmYuV0dCUywgY29sb3VyPXRocmVzaG9sZF8yNSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMTYsIGFscGhhPTAuNiwgc2l6ZT0yKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtMjUsIDI1KSwgbGluZXR5cGU9ImRvdHRlZCIpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGMoLTI1LCAyNSksIGxpbmV0eXBlPSJkb3R0ZWQiKSsKICB5bGFiKCJXZWlnaHRlZCBNZWFuIE1ldGh5bGF0aW9uIERpZmZlcmVuY2UgV0dCUyIpICsKICB4bGFiKCJXZWlnaHRlZCBNZWFuIE1ldGh5bGF0aW9uIERpZmZlcmVuY2UgVGFyZ2V0ZWQgU2VxdWVuY2luZyIpICsKICBsYWJzKHRpdGxlID0gIkRNIFRpbGVzIiwgY29sb3VyPSJUaHJlc2hvbGQiKSArCiAgc3RhdF9jb3IobWV0aG9kPSJwZWFyc29uIikrIAogIHhsaW0oLTkwLCA5MCkgKwogIHlsaW0oLTkwLCA5MCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSwgYXNwZWN0LnJhdGlvID0gMSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzkxOTQ5NCIsICIjN0NBRTAwIikpKwogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoY29uZGl0aW9uKSkKCmFubm90YXRlX2ZpZ3VyZShnZ2FycmFuZ2UocDUwLCBwNTEgLCBucm93PTIsIG5jb2w9MSwgbGFiZWxzPSJBVVRPIiwgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIGxlZ2VuZD0icmlnaHQiKSwgdGV4dF9ncm9iKCJMb2ctQmFja3RyYW5zZm9ybWVkLCBRdWFudGlsZSBOb3JtYWxpc2VkIGFuZCBDb21CYXQiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKCmBgYApgYGB7ciBBZGRfcV92YWx1ZV90b193ZWlnaHRlZF9kaWZmZXJlbmNlX29mX21lYW4sIGZpZy5kaW09YygxMCw1KX0KI0FkZCBxdmFsdWUgdG8gZGF0YWZyYW1lIGFuZCBjYWxjdWxhdGUgaWYgdGhyZXNob2xkIGZvciBxdmFsdWUgYmVsb3cgMC4wMQpvdmVybGFwX0RNX2xvZ19ub3JtYWxpc2VkX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2Vfbm9fbG9nX3dlaWdodGVkX3F2YWx1ZXMgPC0gb3ZlcmxhcF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ193ZWlnaHRlZCAlPiUgCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCB0aWxlcywgY29uZGl0aW9uLCBzZXA9Ii4iKSAlPiUgCiAgbGVmdF9qb2luKGRwbHlyOjpzZWxlY3QoYmluZF9yb3dzKG1ldGh5bERpZmZfdmFsaWRhdGlvbiksIHRpbGVzLCBxdmFsdWUpKSAlPiUgCiAgZHBseXI6OnJlbmFtZShxdmFsdWVfdGFyZ2V0ZWQ9cXZhbHVlKSAlPiUgCiAgbGVmdF9qb2luKGRwbHlyOjpzZWxlY3QoYmluZF9yb3dzKG1ldGh5bERpZmZfV0dCUyksIHRpbGVzLCBxdmFsdWUpKSAlPiUgCiAgZHBseXI6OnJlbmFtZShxdmFsdWVfV0dCUz1xdmFsdWUpICU+JSAKICB0aWR5cjo6c2VwYXJhdGUodGlsZXMsIGludG89YygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiwgImNvbmRpdGlvbiIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZSh0aHJlc2hvbGRfMjVfcXZhbHVlPSBjYXNlX3doZW4odGhyZXNob2xkXzI1ID09InwyNSV8IiAmIHF2YWx1ZV90YXJnZXRlZCA8PTAuMDEgJiBxdmFsdWVfV0dCUyA8MC4wMSB+ICJzaWduaWZpY2FudCIsIFRSVUUgfiAiaW5zaWduaWZpY2FudCIpKSAKCgpwNTEgPC0gb3ZlcmxhcF9ETV9sb2dfbm9ybWFsaXNlZF9jb21iYXRfbG9nX2ZvbGRfY2hhbmdlX25vX2xvZ193ZWlnaHRlZF9xdmFsdWVzICU+JQogIGdncGxvdChhZXMoeCA9IHdlaWdodGVkLm1ldGguZGlmZi50YXJnZXRlZCwgeSA9IHdlaWdodGVkLm1ldGguZGlmZi5XR0JTLCBjb2xvdXI9dGhyZXNob2xkXzI1X3F2YWx1ZSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMTYsIHNpemU9MiwgYWxwaGE9MC42KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtMjUsIDI1KSwgbGluZXR5cGU9ImRvdHRlZCIpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGMoLTI1LCAyNSksIGxpbmV0eXBlPSJkb3R0ZWQiKSsKICB5bGFiKCJXZWlnaHRlZCBNZWFuIE1ldGh5bGF0aW9uIERpZmZlcmVuY2UgV0dCUyIpICsKICB4bGFiKCJXZWlnaHRlZCBNZWFuIE1ldGh5bGF0aW9uIERpZmZlcmVuY2UgVGFyZ2V0ZWQgU2VxdWVuY2luZyIpICsKICBsYWJzKHRpdGxlID0gIkRNIFRpbGVzIiwgY29sb3VyPSJUaHJlc2hvbGQiKSArCiAgc3RhdF9jb3IobWV0aG9kPSJwZWFyc29uIikrIAogIHhsaW0oLTkwLCA5MCkgKwogIHlsaW0oLTkwLCA5MCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSwgYXNwZWN0LnJhdGlvID0gMSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzkxOTQ5NCIsICIjN0NBRTAwIikpKwogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoY29uZGl0aW9uKSkKCnA1MQpgYGAKCgojIyMgQ29tQmF0IHdpdGhvdXQgUXVhbnRpbGUgTm9ybWFsaXNhdGlvbgpgYGB7cn0KbG9uZ19kZl90b19tYXRyaXggPC0gZnVuY3Rpb24oZGYpIHsKICBkZiAlPiUKICAgIGRwbHlyOjpzZWxlY3QoMTozKSAlPiUKICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzYW1wbGVfaWRzLCB2YWx1ZXNfZnJvbSA9IGxvZ190cmFuc2ZfcGVyY19tZXRoKSAlPiUKICAgIGNvbHVtbl90b19yb3duYW1lcygidGlsZXMiKSAlPiUKICAgIGFzLm1hdHJpeCgpICU+JQogICAgcmV0dXJuKCkKfQoKCmFkZF9tZXRhZGF0YV9tYXRyaXggPC0gZnVuY3Rpb24obXgsIG1ldGFkYXRhX2RmKSB7CiAgbXggJT4lCiAgICBhc190aWJibGUocm93bmFtZXMgPSAidGlsZXMiKSAlPiUKICAgIHBpdm90X2xvbmdlcigtdGlsZXMsIG5hbWVzX3RvID0gInNhbXBsZV9pZHMiLCB2YWx1ZXNfdG8gPSAibG9nX3RyYW5zZl9wZXJjX21ldGgiKSAlPiUKICAgIGxlZnRfam9pbihkcGx5cjo6c2VsZWN0KG1ldGFkYXRhLCBzYW1wbGVfaWRzLCBzZXFfbWV0aG9kLCBjb25kaXRpb24pKSAlPiUKICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB0aWxlcywgdmFsdWVzX2Zyb20gPSBsb2dfdHJhbnNmX3BlcmNfbWV0aCkgJT4lCiAgICByZXR1cm4oKQp9CmBgYAoKIyMjIyBQQ0Egb24gbG9nIHRyYW5zZm9ybWVkIGFuZCBjb21iYXQgZGF0YSBzZXBlcmF0ZSBjb25kaXRpb24gYWxsIGNvbW1vbiB0aWxlcwpgYGB7ciBQQ0FfbG9nX3RyYW5zZm9ybWVkX2FuZF9jb21CYXQsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVycm9yPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpvdmVybGFwX2dyb3VwZWRfbG9nX2NvbWJhdCA8LSBvdmVybGFwX2dyb3VwZWRfbG9nICU+JQogIG1hcCh+IGxvbmdfZGZfdG9fbWF0cml4KC4pICU+JQogIHN2YTo6Q29tQmF0KGRhdCA9IC4sIGJhdGNoID0gYmF0Y2hbY29sbmFtZXMoLildKSAlPiUgIAogICAgYWRkX21ldGFkYXRhX21hdHJpeCguLCBtZXRhZGF0YV9kZiA9IG1ldGFkYXRhKSkKYGBgCgpgYGB7ciwgZmlnLmRpbT1jKDEwLDEwKX0Kb3ZlcmxhcF9ncm91cGVkX2xvZ19jb21iYXRfcGNhX3Bsb3QgPC0gb3ZlcmxhcF9ncm91cGVkX2xvZ19jb21iYXQgJT4lCiAgbWFwMigKICAgIG5hbWVzKC4pLAogICAgfiBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCgueCwgc3RhcnRzX3dpdGgoImNociIpKSksIGRhdGEgPSAueCwgY29sb3VyID0gInNlcV9tZXRob2QiKSArCiAgICAgIGxhYnModGl0bGUgPSAueSwgY29sb3VyPSJTZXF1ZW5jaW5nIFxubWV0aG9kIikgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpCiAgKQoKYW5ub3RhdGVfZmlndXJlKGdnYXJyYW5nZShwbG90bGlzdCA9IG92ZXJsYXBfZ3JvdXBlZF9sb2dfY29tYmF0X3BjYV9wbG90ICwgbnJvdz0yLCBuY29sPTIsIGxhYmVscz0iQVVUTyIsIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCBsZWdlbmQ9InJpZ2h0IiksIHRleHRfZ3JvYigiQ29tQmF0IGluIExvZyBTcGFjZVxuQWxsIENvbW1vbiBUaWxlcyIsIGZhY2UgPSAiYm9sZCIsIHNpemU9MTYpKQoKYGBgCgojIyMjIFBDQSBvbiBsb2cgdHJhbnNmb3JtZWQgYW5kIGNvbWJhdCBkYXRhIGFsbCBkaXNlYXNlcyBhbGwgY29tbW9uIHRpbGVzCmBgYHtyLCBQQ0FfbG9nX3RyYW5zZm9ybWVkX2FuZF9jb21CYXQyLCBtZXNzYWdlPUZBTFNFfQpvdmVybGFwX2xvZ19jb21iYXQgPC0gb3ZlcmxhcF9sb2cgJT4lCiAgbG9uZ19kZl90b19tYXRyaXgoKSAlPiUKICBDb21CYXQoZGF0ID0gLiwgYmF0Y2ggPSBiYXRjaFtjb2xuYW1lcyguKV0pICU+JQogIGFkZF9tZXRhZGF0YV9tYXRyaXgobWV0YWRhdGFfZGYgPSBtZXRhZGF0YSkKYGBgCgpgYGB7cn0KcDM2IDwtIG92ZXJsYXBfbG9nX2NvbWJhdCAlPiUgYXV0b3Bsb3QocHJjb21wKGRwbHlyOjpzZWxlY3QoLiwgc3RhcnRzX3dpdGgoImNociIpKSksIGRhdGEgPSAuLCBjb2xvdXIgPSAiY29uZGl0aW9uIikgKwogIGxhYnMoY29sb3VyPSJDb25kaXRpb24iKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0iYm9sZCIpLCBhc3BlY3QucmF0aW8gPSAxKQoKcDM3IDwtIG92ZXJsYXBfbG9nX2NvbWJhdCAlPiUgYXV0b3Bsb3QocHJjb21wKGRwbHlyOjpzZWxlY3QoLiwgc3RhcnRzX3dpdGgoImNociIpKSksIGRhdGEgPSAuLCBjb2xvdXIgPSAic2VxX21ldGhvZCIpICsKICBsYWJzKGNvbG91cj0iU2VxdWVuY2luZyBcbm1ldGhvZCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSJib2xkIiksIGFzcGVjdC5yYXRpbyA9IDEpCgpwNTUgPC0gb3ZlcmxhcF9sb2dfY29tYmF0ICU+JSBhdXRvcGxvdChwcmNvbXAoZHBseXI6OnNlbGVjdCguLCBzdGFydHNfd2l0aCgiY2hyIikpKSwgZGF0YSA9IC4sIHNoYXBlID0gInNlcV9tZXRob2QiLCBjb2xvdXI9ImNvbmRpdGlvbiIpICsKICBsYWJzKHRpdGxlID0gIkNvbUJhdCBpbiBMb2cgU3BhY2VcbkFsbCBDb21tb24gVGlsZXMiLCBzaGFwZT0iU2VxdWVuY2luZyBcbm1ldGhvZCIsIGNvbG91cj0iQ29uZGl0aW9uIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSwgYXNwZWN0LnJhdGlvID0gMSkKCiNwbG90X2dyaWQocDM2LCBwMzcsIG5yb3cgPSAxLCBuY29sID0gMiwgbGFiZWxzID0gIkFVVE8iKQphbm5vdGF0ZV9maWd1cmUoZ2dhcnJhbmdlKHAzNiwgcDM3ICwgbnJvdz0xLCBuY29sPTIsIGxhYmVscz0iQVVUTyIpLCB0ZXh0X2dyb2IoIkNvbUJhdCBpbiBMb2cgU3BhY2VcbkFsbCBDb21tb24gVGlsZXMiLCBmYWNlID0gImJvbGQiLCBzaXplPTE2KSkKCnA1NQpgYGAKCmBgYHtyIFBDQSBvbiBsb2cgdHJhbnNmb3JtZWQgYW5kIGNvbWJhdCBkYXRhIGFsbCBkaXNlYXNlcyBETSB0aWxlcywgZmlnLmRpbT1jKDEwLDEwKX0Kb3ZlcmxhcF9ETV9ncm91cGVkX2xvZ19jb21iYXQgPC1vdmVybGFwX2dyb3VwZWRfbG9nX2NvbWJhdCAlPiUKICBtYXAofiBwaXZvdF9sb25nZXIoLiwgLWMoc2FtcGxlX2lkcywgY29uZGl0aW9uLCBzZXFfbWV0aG9kKSwgbmFtZXNfdG8gPSAidGlsZXMiLCB2YWx1ZXNfdG8gPSAibG9nX3RyYW5zZl9wZXJjX21ldGgiKSU+JQogIHRpZHlyOjp1bml0ZSh0aWxlcywgdGlsZXMsIGNvbmRpdGlvbiwgc2VwPSIuIikgJT4lCiAgZHBseXI6OmZpbHRlcih0aWxlcyAlaW4lIGMoZGlmZl9tZXRoX3RpbGVzKSkgJT4lCiAgdGlkeXI6OnNlcGFyYXRlKHRpbGVzLCBpbnRvID0gYygiY2hyb20iLCAic3RhcnQiLCAiZW5kIiwgImNvbmRpdGlvbiIpLCBzZXAgPSAiXFwuIikgJT4lCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCBjaHJvbSwgc3RhcnQsIGVuZCwgc2VwPSIuIikgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB0aWxlcywgdmFsdWVzX2Zyb20gPSBsb2dfdHJhbnNmX3BlcmNfbWV0aCkpCgpvdmVybGFwX0RNX2dyb3VwZWRfbG9nX2NvbWJhdDwtb3ZlcmxhcF9ETV9ncm91cGVkX2xvZ19jb21iYXRbMjo0XQpvdmVybGFwX0RNX2dyb3VwZWRfbG9nX2NvbWJhdF9wY2FfcGxvdCA8LSBvdmVybGFwX0RNX2dyb3VwZWRfbG9nX2NvbWJhdCU+JQogIG1hcDIoCiAgICBuYW1lcyguKSwKICAgIH4gYXV0b3Bsb3QocHJjb21wKGRwbHlyOjpzZWxlY3QoLngsIHN0YXJ0c193aXRoKCJjaHIiKSkpLCBkYXRhID0gLngsIGNvbG91ciA9ICJzZXFfbWV0aG9kIikgKwogICAgICBsYWJzKHRpdGxlID0gLnksIGNvbG91cj0iU2VxdWVuY2luZyBcbm1ldGhvZCIpICsKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0iYm9sZCIpLCBhc3BlY3QucmF0aW8gPSAxKQogICkKCmFubm90YXRlX2ZpZ3VyZShnZ2FycmFuZ2UocGxvdGxpc3QgPSBvdmVybGFwX0RNX2dyb3VwZWRfbG9nX2NvbWJhdF9wY2FfcGxvdCAsIG5yb3c9MiwgbmNvbD0yLCBsYWJlbHM9IkFVVE8iLCBjb21tb24ubGVnZW5kID0gVFJVRSwgbGVnZW5kPSJyaWdodCIpLCB0ZXh0X2dyb2IoIkNvbUJhdCBpbiBMb2cgU3BhY2VcbkRNIFRpbGVzIiwgZmFjZSA9ICJib2xkIiwgc2l6ZT0xNikpCgpgYGAKCiMjIyMgQ2FsY3VsYXRlIGxvZyBmb2xkIGNoYW5nZSBmb3IgY29tQmF0IGRhdGEgc2NhdHRlcnBsb3QKYGBge3IgTG9nX2ZvbGRfY2hhbmdlX2NvbUJhdF9TY2F0dGVycGxvdCwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CgpvdmVybGFwX2xvZ19jb21iYXRfbG9nX2ZvbGRfY2hhbmdlIDwtIG92ZXJsYXBfbG9nICU+JSBjYWxjX2xvZ19mb2xkX2NoYW5nZSgpCgpvdmVybGFwX0RNX2xvZ19jb21iYXRfbG9nX2ZvbGRfY2hhbmdlIDwtIG92ZXJsYXBfbG9nX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2UgJT4lCiAgdGlkeXI6OnVuaXRlKHRpbGVzLCB0aWxlcywgY29uZGl0aW9uLCBzZXAgPSAiLiIpICU+JQogIGRwbHlyOjpmaWx0ZXIodGlsZXMgJWluJSBjKGRpZmZfbWV0aF90aWxlcykpICU+JQogIHRpZHlyOjpzZXBhcmF0ZSh0aWxlcywgaW50byA9IGMoImNocm9tIiwgInN0YXJ0IiwgImVuZCIsICJjb25kaXRpb24iKSwgc2VwID0gIlxcLiIpCgojIFBsb3QKcDM4IDwtIG92ZXJsYXBfRE1fbG9nX2NvbWJhdF9sb2dfZm9sZF9jaGFuZ2UgJT4lIGdncGxvdChhZXMoeCA9IGxvZ19mb2xkX2NoYW5nZV90YXJnZXRlZCwgeSA9IGxvZ19mb2xkX2NoYW5nZV9XR0JTKSkgKwogIGdlb21fcG9pbnQoY29sb3VyID0gIiM3Q0FFMDAiLCBzaGFwZSA9IDE2LCBzaXplPTIsIGFscGhhPTAuNikgKwogIHlsYWIoImxvZyBmb2xkIGNoYW5nZSBXR0JTIikgKwogIHhsYWIoImxvZyBmb2xkIGNoYW5nZSBUYXJnZXRlZCBTZXF1ZW5jaW5nIikgKwogIGxhYnModGl0bGUgPSAiQ29tQmF0IGluIExvZyBTcGFjZVxuQWxsIENvbW1vbiBUaWxlcyIpICsKICBzdGF0X2NvcihtZXRob2Q9InBlYXJzb24iKSsgIAogIHlsaW0oLTUsIDUpICsKICB4bGltKC01LCArNSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9ImJvbGQiKSwgYXNwZWN0LnJhdGlvID0gMSkgKwogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoY29uZGl0aW9uKSkKCnAzOApgYGAKCiMjIyMgT3ZlcnZpZXcgUGxvdDogUENBIEdyaWQgYWxsIGNvbW1vbiB0aWxlcwpgYGB7ciBNYWtlX1BDQV9ncmlkLCBmaWcuZGltPWMoMTAsNy41KX0KZGF0YSA8LSBsaXN0KCJMb2ciID0gb3ZlcmxhcF9ncm91cGVkX2xvZ19wY2EsICJDb21CYXQiPW92ZXJsYXBfZ3JvdXBlZF9sb2dfY29tYmF0LCAiUXVhbnRpbGUgTm9ybWFsaXNhdGlvbiBcbisgQ29tQmF0IiA9IG92ZXJsYXBfZ3JvdXBlZF9sb2dfbm9ybWFsaXNlZF9jb21iYXRfcGNhKSAlPiUKICBtYXAoYmluZF9yb3dzLCAuaWQgPSAiY29uZGl0aW9uMiIpICU+JQogIG1hcCh+IGJpbmRfY29scygKICAgIGRwbHlyOjpzZWxlY3QoLngsICFzdGFydHNfd2l0aCgiY2hyIikpLCBwcmNvbXAoZHBseXI6OnNlbGVjdCgueCwgc3RhcnRzX3dpdGgoImNociIpKSkkeAogICkpICU+JQogIGJpbmRfcm93cyguaWQgPSAibm9ybWFsaXphdGlvbiIpICU+JQogIG11dGF0ZShub3JtYWxpemF0aW9uID0gZmFjdG9yKG5vcm1hbGl6YXRpb24sIGxldmVscyA9IGMoICJMb2ciLCAiQ29tQmF0IiwgIlF1YW50aWxlIE5vcm1hbGlzYXRpb24gXG4rIENvbUJhdCIpKSkKCmdncGxvdChkYXRhLCBhZXMoUEMxLCBQQzIsIGNvbG91ciA9IGNvbmRpdGlvbiwgc2hhcGU9c2VxX21ldGhvZCkpICsKICBnZW9tX3BvaW50KHNpemU9MikgKwogIGZhY2V0X2dyaWQobm9ybWFsaXphdGlvbiB+IGNvbmRpdGlvbjIsIG1hcmdpbnMgPSAiY29uZGl0aW9uMiIsIHNjYWxlcyA9ICJmcmVlIikgKwogIGxhYnMoc2hhcGU9IlNlcXVlbmNpbmcgbWV0aG9kIiwgY29sb3VyID0gIkNvbmRpdGlvbiIgKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSkrCiAgc2NhbGVfeF9jb250aW51b3VzKHNlYy5heGlzID0gc2VjX2F4aXMofiAuICwgbmFtZSA9ICJBbGwgQ29tbW9uIFRpbGVzIiwgYnJlYWtzID0gTlVMTCwgbGFiZWxzID0gTlVMTCkpCgpgYGAKCiMjIyBNYWtlIFB1YmxpY2F0aW9uIEZpZ3VyZXMKYGBge3IgTWFrZV9QdWJsaWNhdGlvbl9GaWd1cmVzfQoKZmlndXJlXzYgPC0gZ2dhcnJhbmdlKHA2NiwgcDY5LCBucm93PTIsIGxhYmVscz1jKCJBIiwgIkIiKSkgIApnZ3NhdmUoYmcgPSJ3aGl0ZSIsCiIvbG9jYWwvQUFrYWxpbl9jYXJkaWFjL1Jlc3VsdHMvY2FyZGlhYy9QbG90cy9GaWd1cmU2LnBuZyIsCmRldmljZSA9ICJwbmciLApwbG90ID0gZmlndXJlXzYKKQoKCmZpZ3VyZVM2IDwtIGdnYXJyYW5nZShwNywKICAgICAgICAgIGdnYXJyYW5nZShwMzIsIHAzNSwgbmNvbCA9IDIsIGxhYmVscyA9YygiQiIsICJDIikpLAogICAgICAgICAgbnJvdz0yLAogICAgICAgICAgbGFiZWxzPSJBIikKZ2dzYXZlKGJnID0id2hpdGUiLAoiL2xvY2FsL0FBa2FsaW5fY2FyZGlhYy9SZXN1bHRzL2NhcmRpYWMvUGxvdHMvRmlndXJlUzYucGRmIiwKZGV2aWNlID0gInBkZiIsCnBsb3QgPSBmaWd1cmVTNQopCmBgYAo=